QinQ API extension implementation in the Neutron server
This patch implements 'qinq' API extension in the Neutron server. It means that this new attribute is now added for the "vlan" networks to the network dict and returned through the API. This patch also adds validation that both "vlan_transparent" and "qinq" aren't enabled for the same network at the same time as this is not supported. This patch adds all the necessary bits to store value of the new attribute in the Neutron DB and to add support for it to the Network OVO. Finally it also adds check_vlan_qinq() method to all mechanism drivers which are in-tree. For now all of them declare that QinQ vlans are not supported. Related-Bug: #1915151 Change-Id: I427edfd580eb06aa4f6904f90ff28cf8b5267397
This commit is contained in:
parent
0632996b17
commit
e20ef3fa86
@ -128,6 +128,10 @@ core_opts = [
|
||||
cfg.BoolOpt('vlan_transparent', default=False,
|
||||
help=_('If True, then allow plugins that support it to '
|
||||
'create VLAN transparent networks.')),
|
||||
cfg.BoolOpt('vlan_qinq', default=False,
|
||||
help=_('If True, then allow plugins that support it to '
|
||||
'create VLAN transparent networks using 0x8a88 '
|
||||
'ethertype.')),
|
||||
cfg.BoolOpt('filter_validation', default=True,
|
||||
help=_('If True, then allow plugins to decide '
|
||||
'whether to perform validations on filter parameters. '
|
||||
|
@ -0,0 +1,35 @@
|
||||
# Copyright 2024 OpenStack Foundation
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# Add qinq column to the Network table
|
||||
#
|
||||
# Revision ID: ad80a9f07c5c
|
||||
# Revises: 5bcb7b31ec7d
|
||||
# Create Date: 2024-12-09 11:27:41.108660
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'ad80a9f07c5c'
|
||||
down_revision = '5bcb7b31ec7d'
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column(
|
||||
'networks',
|
||||
sa.Column('qinq', sa.Boolean(), server_default=None)
|
||||
)
|
@ -1 +1 @@
|
||||
5bcb7b31ec7d
|
||||
ad80a9f07c5c
|
||||
|
@ -321,6 +321,7 @@ class Network(standard_attr.HasStandardAttributes, model_base.BASEV2,
|
||||
status = sa.Column(sa.String(16))
|
||||
admin_state_up = sa.Column(sa.Boolean)
|
||||
vlan_transparent = sa.Column(sa.Boolean, nullable=True)
|
||||
qinq = sa.Column(sa.Boolean, nullable=True)
|
||||
rbac_entries = orm.relationship(rbac_db_models.NetworkRBAC,
|
||||
backref=orm.backref('network',
|
||||
load_on_pending=True),
|
||||
|
27
neutron/db/qinq_db.py
Normal file
27
neutron/db/qinq_db.py
Normal file
@ -0,0 +1,27 @@
|
||||
# Copyright (c) 2024 Red Hat, Inc.
|
||||
#
|
||||
# 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.
|
||||
from neutron_lib.api.definitions import network as net_def
|
||||
from neutron_lib.api.definitions import qinq as qinq_def
|
||||
from neutron_lib.db import resource_extend
|
||||
|
||||
|
||||
@resource_extend.has_resource_extenders
|
||||
class Vlanqinq_db_mixin:
|
||||
"""Mixin class to add vlan QinQ methods to db_base_plugin_v2."""
|
||||
|
||||
@staticmethod
|
||||
@resource_extend.extends([net_def.COLLECTION_NAME])
|
||||
def _extend_network_dict_vlan_qinq(network_res, network_db):
|
||||
network_res[qinq_def.QINQ_FIELD] = network_db.qinq
|
||||
return network_res
|
48
neutron/extensions/qinq.py
Normal file
48
neutron/extensions/qinq.py
Normal file
@ -0,0 +1,48 @@
|
||||
# Copyright (c) 2024 Red Hat, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from neutron_lib.api.definitions import qinq as apidef
|
||||
from neutron_lib.api import extensions as api_extensions
|
||||
from neutron_lib.api import validators
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _disable_extension_by_config(aliases):
|
||||
if not cfg.CONF.vlan_qinq:
|
||||
if apidef.ALIAS in aliases:
|
||||
aliases.remove(apidef.ALIAS)
|
||||
LOG.info('Disabled VLAN QinQ extension.')
|
||||
|
||||
|
||||
def get_qinq(network):
|
||||
"""Get the value of vlan_qinq from a network if set.
|
||||
|
||||
:param network: The network dict to retrieve the value of vlan_qinq
|
||||
from.
|
||||
:returns: The value of vlan_qinq from the network dict if set in
|
||||
the dict, otherwise False is returned.
|
||||
"""
|
||||
return (network[apidef.QINQ_FIELD]
|
||||
if (apidef.QINQ_FIELD in network and
|
||||
validators.is_attr_set(network[apidef.QINQ_FIELD]))
|
||||
else False)
|
||||
|
||||
|
||||
class Qinq(api_extensions.APIExtensionDescriptor):
|
||||
"""Extension class supporting vlan QinQ networks."""
|
||||
|
||||
api_definition = apidef
|
@ -200,7 +200,8 @@ class ExternalNetwork(base.NeutronDbObject):
|
||||
class Network(rbac_db.NeutronRbacObject):
|
||||
# Version 1.0: Initial version
|
||||
# Version 1.1: Changed 'mtu' to be not nullable
|
||||
VERSION = '1.1'
|
||||
# Version 1.2: Added 'qinq' field
|
||||
VERSION = '1.2'
|
||||
|
||||
rbac_db_cls = NetworkRBAC
|
||||
db_model = models_v2.Network
|
||||
@ -212,6 +213,7 @@ class Network(rbac_db.NeutronRbacObject):
|
||||
'status': obj_fields.StringField(nullable=True),
|
||||
'admin_state_up': obj_fields.BooleanField(nullable=True),
|
||||
'vlan_transparent': obj_fields.BooleanField(nullable=True),
|
||||
'qinq': obj_fields.BooleanField(nullable=True),
|
||||
# TODO(ihrachys): consider converting to a field of stricter type
|
||||
'availability_zone_hints': obj_fields.ListOfStringsField(
|
||||
nullable=True),
|
||||
@ -337,6 +339,8 @@ class Network(rbac_db.NeutronRbacObject):
|
||||
# mtu will not be nullable after
|
||||
raise exception.IncompatibleObjectVersion(
|
||||
objver=target_version, objname=self.__class__.__name__)
|
||||
if _target_version < (1, 2):
|
||||
primitive.pop('qinq', None)
|
||||
|
||||
|
||||
@base.NeutronObjectRegistry.register
|
||||
|
@ -60,6 +60,10 @@ class L2populationMechanismDriver(api.MechanismDriver):
|
||||
"""L2population driver vlan transparency support."""
|
||||
return True
|
||||
|
||||
def check_vlan_qinq(self, context):
|
||||
"""L2population driver doesn't support vlan transparency."""
|
||||
return False
|
||||
|
||||
def _get_ha_port_agents_fdb(
|
||||
self, context, network_id, router_id):
|
||||
other_fdb_ports = {}
|
||||
|
@ -60,6 +60,10 @@ class MacvtapMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
|
||||
"""Macvtap driver vlan transparency support."""
|
||||
return False
|
||||
|
||||
def check_vlan_qinq(self, context):
|
||||
"""Currently Macvtap driver doesn't support QinQ vlan."""
|
||||
return False
|
||||
|
||||
def _is_live_migration(self, context):
|
||||
# We cannot just check if
|
||||
# context.original['host_id'] != context.current['host_id']
|
||||
|
@ -201,6 +201,10 @@ class SriovNicSwitchMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
|
||||
"""SR-IOV driver vlan transparency support."""
|
||||
return True
|
||||
|
||||
def check_vlan_qinq(self, context):
|
||||
"""Currently SR-IOV driver doesn't support QinQ vlan."""
|
||||
return False
|
||||
|
||||
def _get_vif_details(self, segment):
|
||||
network_type = segment[api.NETWORK_TYPE]
|
||||
if network_type == constants.TYPE_FLAT:
|
||||
|
@ -113,6 +113,10 @@ class OpenvswitchMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
|
||||
"""Currently Openvswitch driver doesn't support vlan transparency."""
|
||||
return False
|
||||
|
||||
def check_vlan_qinq(self, context):
|
||||
"""Currently Openvswitch driver doesn't support QinQ vlan."""
|
||||
return False
|
||||
|
||||
def bind_port(self, context):
|
||||
vnic_type = context.current.get(portbindings.VNIC_TYPE,
|
||||
portbindings.VNIC_NORMAL)
|
||||
|
@ -225,6 +225,10 @@ class OVNMechanismDriver(api.MechanismDriver):
|
||||
return (context.current.get(provider_net.NETWORK_TYPE)
|
||||
in vlan_transparency_network_types)
|
||||
|
||||
def check_vlan_qinq(self, context):
|
||||
"""OVN driver vlan QinQ support."""
|
||||
return False
|
||||
|
||||
def _setup_vif_port_bindings(self):
|
||||
self.supported_vnic_types = ovn_const.OVN_SUPPORTED_VNIC_TYPES
|
||||
self.vif_details = {
|
||||
|
@ -23,6 +23,7 @@ from neutron_lib.db import api as db_api
|
||||
from neutron_lib import exceptions as exc
|
||||
from neutron_lib.exceptions import multiprovidernet as mpnet_exc
|
||||
from neutron_lib.exceptions import placement as place_exc
|
||||
from neutron_lib.exceptions import vlanqinq as qinq_exc
|
||||
from neutron_lib.exceptions import vlantransparent as vlan_exc
|
||||
from neutron_lib.plugins.ml2 import api
|
||||
from oslo_config import cfg
|
||||
@ -469,6 +470,19 @@ class MechanismManager(stevedore.named.NamedExtensionManager):
|
||||
if not driver.obj.check_vlan_transparency(context):
|
||||
raise vlan_exc.VlanTransparencyDriverError()
|
||||
|
||||
def _check_vlan_qinq(self, context):
|
||||
"""Helper method for checking vlan qinq support.
|
||||
|
||||
:param context: context parameter to pass to each method call
|
||||
:raises: neutron_lib.exceptions.qinq.
|
||||
VlanQinqDriverError if any mechanism driver doesn't
|
||||
support vlan transparency.
|
||||
"""
|
||||
if context.current.get('qinq'):
|
||||
for driver in self.ordered_mech_drivers:
|
||||
if not driver.obj.check_vlan_qinq(context):
|
||||
raise qinq_exc.VlanQinqDriverError()
|
||||
|
||||
def start_driver_rpc_listeners(self):
|
||||
servers = []
|
||||
for driver in self.ordered_mech_drivers:
|
||||
@ -529,6 +543,7 @@ class MechanismManager(stevedore.named.NamedExtensionManager):
|
||||
that all mechanism drivers are called in this case.
|
||||
"""
|
||||
self._check_vlan_transparency(context)
|
||||
self._check_vlan_qinq(context)
|
||||
self._call_on_drivers("create_network_precommit", context,
|
||||
raise_db_retriable=True)
|
||||
|
||||
|
@ -52,6 +52,7 @@ from neutron_lib.api.definitions import port_security as psec
|
||||
from neutron_lib.api.definitions import portbindings
|
||||
from neutron_lib.api.definitions import portbindings_extended as pbe_ext
|
||||
from neutron_lib.api.definitions import provider_net
|
||||
from neutron_lib.api.definitions import qinq as qinq_apidef
|
||||
from neutron_lib.api.definitions import quota_check_limit
|
||||
from neutron_lib.api.definitions import rbac_address_groups as rbac_ag_apidef
|
||||
from neutron_lib.api.definitions import rbac_address_scope
|
||||
@ -128,12 +129,14 @@ from neutron.db import extradhcpopt_db
|
||||
from neutron.db.models import securitygroup as sg_models
|
||||
from neutron.db import models_v2
|
||||
from neutron.db import provisioning_blocks
|
||||
from neutron.db import qinq_db
|
||||
from neutron.db import securitygroups_rpc_base as sg_db_rpc
|
||||
from neutron.db import segments_db
|
||||
from neutron.db import subnet_service_type_mixin
|
||||
from neutron.db import vlantransparent_db
|
||||
from neutron.extensions import dhcpagentscheduler as dhcp_ext
|
||||
from neutron.extensions import filter_validation
|
||||
from neutron.extensions import qinq
|
||||
from neutron.extensions import quota_check_limit_default
|
||||
from neutron.extensions import security_groups_default_rules as \
|
||||
sg_default_rules_ext
|
||||
@ -186,7 +189,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
extradhcpopt_db.ExtraDhcpOptMixin,
|
||||
address_scope_db.AddressScopeDbMixin,
|
||||
subnet_service_type_mixin.SubnetServiceTypeMixin,
|
||||
address_group_db.AddressGroupDbMixin):
|
||||
address_group_db.AddressGroupDbMixin,
|
||||
qinq_db.Vlanqinq_db_mixin):
|
||||
|
||||
"""Implement the Neutron L2 abstractions using modules.
|
||||
|
||||
@ -253,6 +257,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
sg_default_rules_ext.ALIAS,
|
||||
sg_rules_default_sg.ALIAS,
|
||||
subnet_ext_net_def.ALIAS,
|
||||
qinq_apidef.ALIAS,
|
||||
]
|
||||
|
||||
# List of agent types for which all binding_failed ports should try to be
|
||||
@ -268,6 +273,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
vlantransparent._disable_extension_by_config(aliases)
|
||||
filter_validation._disable_extension_by_config(aliases)
|
||||
dhcp_ext.disable_extension_by_config(aliases)
|
||||
qinq._disable_extension_by_config(aliases)
|
||||
self._aliases = self._filter_extensions_by_mech_driver(aliases)
|
||||
return self._aliases
|
||||
|
||||
@ -1212,10 +1218,23 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
self.type_manager.extend_network_dict_provider(context, result)
|
||||
|
||||
# Update the transparent vlan if configured
|
||||
is_vlan_transparent = None
|
||||
if extensions.is_extension_supported(self, 'vlan-transparent'):
|
||||
vlt = vlan_apidef.get_vlan_transparent(net_data)
|
||||
net_db['vlan_transparent'] = vlt
|
||||
result['vlan_transparent'] = vlt
|
||||
is_vlan_transparent = vlan_apidef.get_vlan_transparent(
|
||||
net_data)
|
||||
net_db['vlan_transparent'] = is_vlan_transparent
|
||||
result['vlan_transparent'] = is_vlan_transparent
|
||||
# Update the vlan QinQ if configured
|
||||
qinq_value = None
|
||||
if extensions.is_extension_supported(self, qinq_apidef.ALIAS):
|
||||
qinq_value = qinq.get_qinq(net_data)
|
||||
net_db['qinq'] = qinq_value
|
||||
result['qinq'] = qinq_value
|
||||
# QinQ and vlan_transparent can't be both set to True
|
||||
if is_vlan_transparent and qinq_value:
|
||||
msg = _("Attributes 'vlan_transparent' and 'qinq' can not be "
|
||||
"set to True for the same network.")
|
||||
raise exc.BadRequest(resource='network', msg=msg)
|
||||
az_hints = utils.get_az_hints(net_data)
|
||||
if az_hints:
|
||||
self.validate_availability_zones(context, 'network', az_hints)
|
||||
|
132
neutron/tests/unit/extensions/test_qinq.py
Normal file
132
neutron/tests/unit/extensions/test_qinq.py
Normal file
@ -0,0 +1,132 @@
|
||||
# Copyright (c) 2024 Red Hat, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from neutron_lib.api.definitions import provider_net
|
||||
from neutron_lib.api.definitions import qinq as qinq_apidef
|
||||
from neutron_lib.api.definitions import vlantransparent as vlan_apidef
|
||||
from oslo_config import cfg
|
||||
from webob import exc as web_exc
|
||||
|
||||
from neutron.db import qinq_db
|
||||
from neutron.plugins.ml2 import plugin as ml2_plugin
|
||||
from neutron.tests.common import test_db_base_plugin_v2
|
||||
from neutron.tests.unit import testlib_api
|
||||
|
||||
|
||||
class QinqExtensionTestPlugin(ml2_plugin.Ml2Plugin,
|
||||
qinq_db.Vlanqinq_db_mixin):
|
||||
"""Test plugin to mixin the VLAN transparent extensions."""
|
||||
|
||||
supported_extension_aliases = [provider_net.ALIAS,
|
||||
qinq_apidef.ALIAS,
|
||||
vlan_apidef.ALIAS]
|
||||
|
||||
|
||||
class QinqExtensionTestCase(test_db_base_plugin_v2.TestNetworksV2):
|
||||
fmt = 'json'
|
||||
|
||||
def setUp(self):
|
||||
plugin = ('neutron.tests.unit.extensions.test_qinq.'
|
||||
'QinqExtensionTestPlugin')
|
||||
|
||||
cfg.CONF.set_override('network_vlan_ranges', 'datacentre',
|
||||
group='ml2_type_vlan')
|
||||
super().setUp(plugin=plugin)
|
||||
|
||||
def test_create_network_with_qinq_attr(self):
|
||||
arg_list = (
|
||||
qinq_apidef.QINQ_FIELD),
|
||||
net_kwargs = {
|
||||
qinq_apidef.QINQ_FIELD: True
|
||||
}
|
||||
with self.network(name='net1', as_admin=True,
|
||||
arg_list=arg_list, **net_kwargs) as net:
|
||||
req = self.new_show_request('networks', net['network']['id'])
|
||||
res = self.deserialize(self.fmt, req.get_response(self.api))
|
||||
self.assertEqual(net['network']['name'],
|
||||
res['network']['name'])
|
||||
self.assertTrue(res['network'][qinq_apidef.QINQ_FIELD])
|
||||
|
||||
def test_create_network_with_bad_qinq_attr(self):
|
||||
arg_list = (
|
||||
qinq_apidef.QINQ_FIELD),
|
||||
net_kwargs = {
|
||||
qinq_apidef.QINQ_FIELD: 'this is not boolean value',
|
||||
}
|
||||
with testlib_api.ExpectedException(
|
||||
web_exc.HTTPClientError) as ctx_manager:
|
||||
with self.network(name='net1', as_admin=True,
|
||||
arg_list=arg_list, **net_kwargs):
|
||||
pass
|
||||
self.assertEqual(web_exc.HTTPClientError.code,
|
||||
ctx_manager.exception.code)
|
||||
|
||||
def test_network_update_with_qinq_exception(self):
|
||||
arg_list = (
|
||||
qinq_apidef.QINQ_FIELD),
|
||||
net_kwargs = {
|
||||
qinq_apidef.QINQ_FIELD: False,
|
||||
}
|
||||
with self.network(name='net1', as_admin=True,
|
||||
arg_list=arg_list, **net_kwargs) as net:
|
||||
self._update('networks', net['network']['id'],
|
||||
{'network': {qinq_apidef.QINQ_FIELD: True}},
|
||||
web_exc.HTTPBadRequest.code)
|
||||
req = self.new_show_request('networks', net['network']['id'])
|
||||
res = self.deserialize(self.fmt, req.get_response(self.api))
|
||||
self.assertEqual(net['network']['name'],
|
||||
res['network']['name'])
|
||||
self.assertFalse(res['network'][qinq_apidef.QINQ_FIELD])
|
||||
|
||||
def _test_create_network_qinq_and_transparent_vlan(self, qinq_value, vlt):
|
||||
arg_list = (
|
||||
qinq_apidef.QINQ_FIELD,
|
||||
vlan_apidef.VLANTRANSPARENT)
|
||||
net_kwargs = {
|
||||
qinq_apidef.QINQ_FIELD: qinq_value,
|
||||
vlan_apidef.VLANTRANSPARENT: vlt,
|
||||
}
|
||||
# Both vlan_transparent and qinq can't be set for the same network
|
||||
if qinq_value and vlt:
|
||||
with testlib_api.ExpectedException(
|
||||
web_exc.HTTPClientError) as ctx_manager:
|
||||
with self.network(name='net1', as_admin=True,
|
||||
arg_list=arg_list, **net_kwargs):
|
||||
pass
|
||||
self.assertEqual(web_exc.HTTPBadRequest.code,
|
||||
ctx_manager.exception.code)
|
||||
return
|
||||
|
||||
# In any other case it should work fine
|
||||
with self.network(name='net1', as_admin=True,
|
||||
arg_list=arg_list, **net_kwargs) as net:
|
||||
req = self.new_show_request('networks', net['network']['id'])
|
||||
res = self.deserialize(self.fmt, req.get_response(self.api))
|
||||
self.assertEqual(net['network']['name'],
|
||||
res['network']['name'])
|
||||
self.assertEqual(qinq_value,
|
||||
res['network'][qinq_apidef.QINQ_FIELD])
|
||||
self.assertEqual(vlt, res['network'][vlan_apidef.VLANTRANSPARENT])
|
||||
|
||||
def test_create_network_qinq_disabled_transparent_vlan_enabled(self):
|
||||
self._test_create_network_qinq_and_transparent_vlan(False, True)
|
||||
|
||||
def test_create_network_qinq_disabled_transparent_vlan_disabled(self):
|
||||
self._test_create_network_qinq_and_transparent_vlan(False, False)
|
||||
|
||||
def test_create_network_qinq_enabled_transparent_vlan_disabled(self):
|
||||
self._test_create_network_qinq_and_transparent_vlan(True, False)
|
||||
|
||||
def test_create_network_qinq_enabled_transparent_vlan_enabled(self):
|
||||
self._test_create_network_qinq_and_transparent_vlan(True, True)
|
@ -260,6 +260,11 @@ class NetworkDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
|
||||
obj = network.Network.get_object(self.context, id=obj.id)
|
||||
self.assertEqual('bar.com', obj.dns_domain)
|
||||
|
||||
def test_v1_2_to_v1_1_drops_qinq_attribute(self):
|
||||
network_obj = self._make_object(self.obj_fields[0])
|
||||
network_v1_1 = network_obj.obj_to_primitive(target_version='1.1')
|
||||
self.assertNotIn('qinq', network_v1_1['versioned_object.data'])
|
||||
|
||||
|
||||
class SegmentHostMappingIfaceObjectTestCase(
|
||||
obj_test_base.BaseObjectIfaceTestCase):
|
||||
|
@ -65,7 +65,7 @@ object_data = {
|
||||
'MeteringLabelRule': '2.0-0ad09894c62e1ce6e868f725158959ba',
|
||||
'Log': '1.0-6391351c0f34ed34375a19202f361d24',
|
||||
'NDPProxy': '1.0-a6597d9caac3bb0d63f943f82e4dda8c',
|
||||
'Network': '1.1-c3e9ecc0618ee934181d91b143a48901',
|
||||
'Network': '1.2-0221c921b40f11b237e6a274984f238a',
|
||||
'NetworkDhcpAgentBinding': '1.1-d9443c88809ffa4c45a0a5a48134b54a',
|
||||
'NetworkDNSDomain': '1.0-420db7910294608534c1e2e30d6d8319',
|
||||
'NetworkPortSecurity': '1.0-b30802391a87945ee9c07582b4ff95e3',
|
||||
|
@ -96,6 +96,11 @@ class LoggerMechanismDriver(api.MechanismDriver):
|
||||
self._log_diff_call("check_vlan_transparency", context)
|
||||
return True
|
||||
|
||||
def check_vlan_qinq(self, context):
|
||||
self._log_network_call("check_vlan_qinq", context)
|
||||
self._log_diff_call("check_vlan_qinq", context)
|
||||
return True
|
||||
|
||||
def _log_subnet_call(self, method_name, context):
|
||||
LOG.info("%(method)s called with subnet settings %(current)s "
|
||||
"(original settings %(original)s)",
|
||||
|
Loading…
x
Reference in New Issue
Block a user