Add scenario tests for the Vlan QinQ feature
This patch adds 2 new scenario tests to test connectivity between VMs
using vlan network with enabled QinQ and with vlan configured inside
VMs.
This is very similar to the "vlan_transparent" option which was already
tested since some time. The only difference is in the ethtype of the
outer vlan packets send through such network. Unfortunately we can't
test ethtype of the outer vlan in the neutron-tempest-plugin tests as
that would require access to the host where VMs runs and test packets on
the physical NICs.
So those new tests are actually the same as the existing tests for the
network with "vlan_transparent" enabled to at least make sure that QinQ
functionality works from the end user point of view.
This patch also enables those new tests for the ML2/OVN job as this is
currently only backend with implemented support for QinQ.
Depends-On: https://review.opendev.org/c/openstack/neutron/+/937633
Related-Bug: #1915151
Change-Id: Icc2b175cf4cfe5c4ca73bb7ccc5a9089a27798c9
diff --git a/neutron_tempest_plugin/common/ip.py b/neutron_tempest_plugin/common/ip.py
index 07bbe69..c5a6135 100644
--- a/neutron_tempest_plugin/common/ip.py
+++ b/neutron_tempest_plugin/common/ip.py
@@ -96,7 +96,7 @@
return self.configure_vlan(addresses, port, vlan_tag, subport_ips,
subport['mac_address'])
- def configure_vlan_transparent(self, port, vlan_tag, ip_addresses):
+ def configure_inner_vlan(self, port, vlan_tag, ip_addresses):
addresses = self.list_addresses()
try:
subport_device = get_vlan_device_name(addresses, ip_addresses)
diff --git a/neutron_tempest_plugin/scenario/test_vlan_transparency.py b/neutron_tempest_plugin/scenario/test_vlan_transparency.py
index 11f12e9..85648bc 100644
--- a/neutron_tempest_plugin/scenario/test_vlan_transparency.py
+++ b/neutron_tempest_plugin/scenario/test_vlan_transparency.py
@@ -30,20 +30,27 @@
MAX_VLAN_ID = 4094
-class VlanTransparencyTest(base.BaseTempestTestCase):
- credentials = ['primary', 'admin']
- force_tenant_isolation = False
+class BaseVlanTest(base.BaseAdminTempestTestCase):
- required_extensions = ['vlan-transparent', 'allowed-address-pairs']
+ """Base class common for the tests for the "vlan_transparent" and "qinq".
+
+ This base class covers common things for the tests for networks with
+ enabled either `qinq` or `vlan_transparent` attributes. Those 2 attributes
+ are functionally the same even from the end user's point of view. The only
+ difference between them is ethtype used for the outer VLAN tag but this
+ can't really be tested in the neutron-tempest-plugin tests.
+ """
+
+ network_kwargs = {}
@classmethod
def resource_setup(cls):
- super(VlanTransparencyTest, cls).resource_setup()
+ super(BaseVlanTest, cls).resource_setup()
# setup basic topology for servers we can log into
cls.rand_name = data_utils.rand_name(
cls.__name__.rsplit('.', 1)[-1])
cls.network = cls.create_network(name=cls.rand_name,
- vlan_transparent=True)
+ **cls.network_kwargs)
cls.subnet = cls.create_subnet(network=cls.network,
name=cls.rand_name)
cls.router = cls.create_router_by_client()
@@ -63,7 +70,7 @@
@classmethod
def skip_checks(cls):
- super(VlanTransparencyTest, cls).skip_checks()
+ super().skip_checks()
if not (CONF.neutron_plugin_options.advanced_image_ref or
CONF.neutron_plugin_options.default_image_is_advanced):
raise cls.skipException(
@@ -89,12 +96,11 @@
networks=[{'port': self.vm_ports[-1]['id']}],
name=server_name)['server']
- def _configure_vlan_transparent(self, port, ssh_client,
- vlan_tag, vlan_ip):
+ def _configure_inner_vlan(self, port, ssh_client, vlan_tag, vlan_ip):
ip_command = ip.IPCommand(ssh_client=ssh_client)
addresses = ip_command.list_addresses(port=port)
port_iface = ip.get_port_device_name(addresses, port)
- subport_iface = ip_command.configure_vlan_transparent(
+ subport_iface = ip_command.configure_inner_vlan(
port=port, vlan_tag=vlan_tag, ip_addresses=[vlan_ip])
for address in ip_command.list_addresses(ip_addresses=vlan_ip):
@@ -113,8 +119,9 @@
username=username,
pkey=self.keypair['private_key'])
- def _test_basic_vlan_transparency_connectivity(
+ def _test_basic_inner_vlan_connectivity(
self, port_security=True, use_allowed_address_pairs=False):
+ self._ensure_ethtype()
vlan_tag = data_utils.rand_int_id(start=MIN_VLAN_ID, end=MAX_VLAN_ID)
vlan_ipmask_template = '192.168.%d.{ip_last_byte}/24' % (vlan_tag %
256)
@@ -139,10 +146,10 @@
self._create_ssh_client(floating_ip=floating_ips[i]))
self.check_connectivity(ssh_client=ssh_clients[i])
- self._configure_vlan_transparent(port=self.vm_ports[-1],
- ssh_client=ssh_clients[i],
- vlan_tag=vlan_tag,
- vlan_ip=vlan_ipmasks[i])
+ self._configure_inner_vlan(port=self.vm_ports[-1],
+ ssh_client=ssh_clients[i],
+ vlan_tag=vlan_tag,
+ vlan_ip=vlan_ipmasks[i])
if port_security:
# Ping from vm0 to vm1 via VLAN interface should fail because
@@ -173,12 +180,63 @@
self.vm_ports[-2]['fixed_ips'][0]['ip_address'],
servers=vms)
+
+class VlanTransparencyTest(BaseVlanTest):
+ credentials = ['primary', 'admin']
+ force_tenant_isolation = False
+
+ required_extensions = ['vlan-transparent', 'allowed-address-pairs']
+
+ network_kwargs = {'vlan_transparent': True}
+
+ def _ensure_ethtype(self):
+ self.assertTrue(self.network.get('vlan_transparent'))
+ self.assertFalse(self.network.get('qinq'))
+
@decorators.idempotent_id('a2694e3a-6d4d-4a23-9fcc-c3ed3ef37b16')
def test_vlan_transparent_port_sec_disabled(self):
- self._test_basic_vlan_transparency_connectivity(
+ self._test_basic_inner_vlan_connectivity(
port_security=False, use_allowed_address_pairs=False)
@decorators.idempotent_id('2dd03b4f-9c20-4cda-8c6a-40fa453ec69a')
def test_vlan_transparent_allowed_address_pairs(self):
- self._test_basic_vlan_transparency_connectivity(
+ self._test_basic_inner_vlan_connectivity(
+ port_security=True, use_allowed_address_pairs=True)
+
+
+class VlanQinqTest(BaseVlanTest):
+ credentials = ['primary', 'admin']
+ force_tenant_isolation = False
+
+ required_extensions = ['qinq', 'allowed-address-pairs']
+
+ network_kwargs = {
+ 'qinq': True,
+ 'provider_network_type': 'vlan'}
+
+ @classmethod
+ def resource_setup(cls):
+ cls.network_kwargs['provider_physical_network'] = (
+ CONF.neutron_plugin_options.provider_vlans[0])
+ super().resource_setup()
+
+ @classmethod
+ def skip_checks(cls):
+ super().skip_checks()
+ if not CONF.neutron_plugin_options.provider_vlans:
+ raise cls.skipException(
+ 'Physical network is required to run these tests.')
+
+ def _ensure_ethtype(self):
+ self.assertFalse(self.network.get('vlan_transparent'))
+ self.assertTrue(self.network.get('qinq'))
+
+ @decorators.idempotent_id('ae78398e-9242-46b4-a5fc-227581821fca')
+ def test_vlan_transparent_port_sec_disabled(self):
+ self._test_basic_inner_vlan_connectivity(
+ port_security=False, use_allowed_address_pairs=False)
+
+ @decorators.idempotent_id('6ca983cd-b1c5-4e2c-949e-4be8ffa22a9c')
+ def test_vlan_transparent_allowed_address_pairs(self):
+ self._test_basic_inner_vlan_connectivity(
port_security=True, use_allowed_address_pairs=True)
diff --git a/zuul.d/master_jobs.yaml b/zuul.d/master_jobs.yaml
index f726ee5..bf88ac8 100644
--- a/zuul.d/master_jobs.yaml
+++ b/zuul.d/master_jobs.yaml
@@ -628,6 +628,7 @@
vars:
network_api_extensions_ovn:
- vlan-transparent
+ - qinq
- external-gateway-multihoming
devstack_localrc:
Q_AGENT: ovn
@@ -678,6 +679,7 @@
DEFAULT:
enable_dvr: false
vlan_transparent: true
+ vlan_qinq: true
/$NEUTRON_CORE_PLUGIN_CONF:
ml2:
type_drivers: local,flat,vlan,geneve
@@ -688,6 +690,7 @@
network-feature-enabled:
available_features: "{{ network_available_features | join(',') }}"
neutron_plugin_options:
+ provider_vlans: public,
available_type_drivers: local,flat,vlan,geneve
is_igmp_snooping_enabled: True
firewall_driver: ovn