![Bence Romsics](/assets/img/avatar_default.png)
When using neutron trunks, the tpi port is meant to be put in the dead vlan, not the tap, therefore 1) we no longer add taps in trunk bridges to the dead vlan in order to avoid bug #2069543. While working on this I realized a related problem: In neutron we changed how the dead vlan is handled. Instead of simply setting tag=4095 we set (beyond having a drop rule for tag 4095): tag : 4095 trunks : [4095] vlan_mode : trunk We do this not with the intention of making the port a trunk, but with the intention of dropping all traffic arriving on the port. For details please see the following patches: neutron $ git log --oneline --no-merges --grep='dead vlan' -2 0ddca28454 Make sure "dead vlan" ports cannot transmit packets 7aae31c9f9 Make the dead vlan actually dead Therefore 2) this patch also starts handling ports in the dead vlan as neutron does. Change-Id: I4f80d94bc1f346fd0a7ad0b9d684792f1451cf24 Closes-Bug: #2069543 Related-Bug: #1734320 Related-Bug: #1930414 Related-Bug: #1959564
221 lines
8.1 KiB
Python
221 lines
8.1 KiB
Python
# 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.
|
|
|
|
import testscenarios
|
|
import time
|
|
from unittest import mock
|
|
|
|
from oslo_concurrency import processutils
|
|
from oslo_config import cfg
|
|
from oslo_utils import uuidutils
|
|
|
|
from os_vif import objects
|
|
|
|
from vif_plug_ovs import constants
|
|
from vif_plug_ovs import ovs
|
|
from vif_plug_ovs.ovsdb import ovsdb_lib
|
|
from vif_plug_ovs import privsep
|
|
from vif_plug_ovs.tests.functional import base
|
|
|
|
|
|
CONF = cfg.CONF
|
|
|
|
|
|
@privsep.vif_plug.entrypoint
|
|
def run_privileged(*full_args):
|
|
return processutils.execute(*full_args)[0].rstrip()
|
|
|
|
|
|
# derived from test_impl_pyroute2
|
|
|
|
def exist_device(device):
|
|
try:
|
|
run_privileged('ip', 'link', 'show', device)
|
|
return True
|
|
except processutils.ProcessExecutionError as e:
|
|
if e.exit_code == 1:
|
|
return False
|
|
raise
|
|
|
|
|
|
def add_device(device, dev_type, peer=None, link=None,
|
|
vlan_id=None):
|
|
if 'vlan' == dev_type:
|
|
run_privileged('ip', 'link', 'add', 'link', link,
|
|
'name', device, 'type', dev_type, 'vlan', 'id',
|
|
vlan_id)
|
|
elif 'veth' == dev_type:
|
|
run_privileged('ip', 'link', 'add', device, 'type', dev_type,
|
|
'peer', 'name', peer)
|
|
elif 'dummy' == dev_type:
|
|
run_privileged('ip', 'link', 'add', device, 'type', dev_type)
|
|
# ensure that the device exists to prevent racing with other ip commands
|
|
for _ in range(10):
|
|
if exist_device(device):
|
|
return
|
|
time.sleep(0.1)
|
|
|
|
|
|
def del_device(device):
|
|
if exist_device(device):
|
|
run_privileged('ip', 'link', 'del', device)
|
|
|
|
|
|
class TestOVSPlugin(testscenarios.WithScenarios,
|
|
base.VifPlugOvsBaseFunctionalTestCase):
|
|
|
|
scenarios = [
|
|
('native', {'interface': 'native'}),
|
|
('vsctl', {'interface': 'vsctl'})
|
|
]
|
|
|
|
def setUp(self):
|
|
super(TestOVSPlugin, self).setUp()
|
|
run_privileged('ovs-vsctl', 'set-manager', 'ptcp:6640')
|
|
self.plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME)
|
|
self.flags(ovsdb_interface=self.interface, group='os_vif_ovs')
|
|
|
|
self.ovs = ovsdb_lib.BaseOVS(CONF.os_vif_ovs)
|
|
self._ovsdb = self.ovs.ovsdb
|
|
|
|
self.profile_ovs = objects.vif.VIFPortProfileOpenVSwitch(
|
|
interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa',
|
|
datapath_type='netdev')
|
|
|
|
self.subnet_bridge_4 = objects.subnet.Subnet(
|
|
cidr='101.168.1.0/24',
|
|
dns=['8.8.8.8'],
|
|
gateway='101.168.1.1',
|
|
dhcp_server='191.168.1.1')
|
|
|
|
self.subnet_bridge_6 = objects.subnet.Subnet(
|
|
cidr='101:1db9::/64',
|
|
gateway='101:1db9::1')
|
|
|
|
self.subnets = objects.subnet.SubnetList(
|
|
objects=[self.subnet_bridge_4,
|
|
self.subnet_bridge_6])
|
|
|
|
self.network_ovs_trunk = objects.network.Network(
|
|
id='437c6db5-4e6f-4b43-b64b-ed6a11ee5ba7',
|
|
bridge='%s01' % constants.TRUNK_BR_PREFIX,
|
|
subnets=self.subnets,
|
|
vlan=99)
|
|
|
|
self.vif_vhostuser_trunk = objects.vif.VIFVHostUser(
|
|
id='b679325f-ca89-4ee0-a8be-6db1409b69ea',
|
|
address='ca:fe:de:ad:be:ef',
|
|
network=self.network_ovs_trunk,
|
|
path='/var/run/openvswitch/vhub679325f-ca',
|
|
mode='client',
|
|
port_profile=self.profile_ovs)
|
|
|
|
self.profile_ovs_system = objects.vif.VIFPortProfileOpenVSwitch(
|
|
interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa',
|
|
datapath_type='system',
|
|
create_port=True)
|
|
|
|
self.network_ovs = objects.network.Network(
|
|
id='437c6db5-4e6f-4b43-b64b-ed6a11ee5ba7',
|
|
bridge='br-qos-' + self.interface,
|
|
subnets=self.subnets,
|
|
vlan=99)
|
|
|
|
self.vif_ovs_port = objects.vif.VIFOpenVSwitch(
|
|
id='b679325f-ca89-4ee0-a8be-6db1409b69ea',
|
|
address='ca:fe:de:ad:be:ef',
|
|
network=self.network_ovs,
|
|
port_profile=self.profile_ovs_system,
|
|
vif_name="qos-port-" + self.interface)
|
|
|
|
self.instance = objects.instance_info.InstanceInfo(
|
|
name='demo',
|
|
uuid='f0000000-0000-0000-0000-000000000001')
|
|
|
|
def test_plug_unplug_ovs_vhostuser_trunk(self):
|
|
trunk_bridge = '%s01' % constants.TRUNK_BR_PREFIX
|
|
self.plugin.plug(self.vif_vhostuser_trunk, self.instance)
|
|
self.addCleanup(self._del_bridge, trunk_bridge)
|
|
self.assertTrue(self._check_bridge(trunk_bridge))
|
|
|
|
other_bridge = 'br-%s' % uuidutils.generate_uuid()
|
|
self._add_bridge(other_bridge)
|
|
self.addCleanup(self._del_bridge, other_bridge)
|
|
self.plugin.unplug(self.vif_vhostuser_trunk, self.instance)
|
|
self.assertTrue(self._check_bridge(other_bridge))
|
|
self.assertFalse(self._check_bridge(trunk_bridge))
|
|
|
|
def test_plug_unplug_ovs_port_with_qos(self):
|
|
bridge = 'br-qos-' + self.interface
|
|
vif_name = "qos-port-" + self.interface
|
|
qos_type = CONF.os_vif_ovs.default_qos_type
|
|
self.addCleanup(self._del_bridge, bridge)
|
|
self.addCleanup(
|
|
self.ovs.delete_ovs_vif_port, bridge, vif_name,
|
|
delete_netdev=False, qos_type=qos_type
|
|
)
|
|
self.addCleanup(del_device, vif_name)
|
|
add_device(vif_name, 'dummy')
|
|
# pluging a vif will create the port and bridge
|
|
# if either does not exist
|
|
self.plugin.plug(self.vif_ovs_port, self.instance)
|
|
self.assertTrue(self._check_bridge(bridge))
|
|
self.assertTrue(self._check_port(vif_name, bridge))
|
|
qos_uuid = self.ovs.get_qos(
|
|
vif_name, qos_type
|
|
)[0]['_uuid']
|
|
self._check_parameter('Port', vif_name, 'qos', qos_uuid)
|
|
self._check_parameter(
|
|
'QoS', str(qos_uuid), 'type', qos_type
|
|
)
|
|
# unpluging a port will not delete the bridge.
|
|
self.plugin.unplug(self.vif_ovs_port, self.instance)
|
|
self.assertTrue(self._check_bridge(bridge))
|
|
self.assertFalse(self._check_port(vif_name, bridge))
|
|
self._check_parameter(
|
|
'QoS', str(qos_uuid), 'type', None
|
|
)
|
|
|
|
def test_plug_br_int_isolate_vif_dead_vlan(self):
|
|
with mock.patch.object(self.plugin.config, 'isolate_vif', True):
|
|
network = objects.network.Network(
|
|
id='5449523c-3a08-11ef-86d6-17149687aa4d',
|
|
bridge='br-5449523c',
|
|
subnets=self.subnets,
|
|
vlan=99)
|
|
vif = objects.vif.VIFOpenVSwitch(
|
|
id='85cb9bc6-3a08-11ef-b2d4-9b7c38edd677',
|
|
address='ca:fe:de:ad:be:ef',
|
|
network=network,
|
|
port_profile=self.profile_ovs_system,
|
|
vif_name="port-85cb9bc6")
|
|
self.plugin.plug(vif, self.instance)
|
|
self.addCleanup(self._del_bridge, 'br-5449523c')
|
|
self._check_parameter('Port', vif.vif_name, 'tag', 4095)
|
|
|
|
def test_plug_trunk_bridge_ignores_isolate_vif(self):
|
|
with mock.patch.object(self.plugin.config, 'isolate_vif', True):
|
|
network = objects.network.Network(
|
|
id='ef98b384-3a0f-11ef-9009-47345fca266f',
|
|
bridge='tbr-ef98b384',
|
|
subnets=self.subnets,
|
|
vlan=99)
|
|
vif = objects.vif.VIFOpenVSwitch(
|
|
id='631f52bc-3a07-11ef-a006-1319ef9d6edd',
|
|
address='ca:fe:de:ad:be:ef',
|
|
network=network,
|
|
port_profile=self.profile_ovs_system,
|
|
vif_name='port-631f52bc')
|
|
self.plugin.plug(vif, self.instance)
|
|
self.addCleanup(self._del_bridge, 'tbr-ef98b384')
|
|
self._check_parameter('Port', vif.vif_name, 'tag', [])
|