You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
6.4 KiB
145 lines
6.4 KiB
# All Rights Reserved.
|
|
#
|
|
# 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 mock
|
|
from oslo_config import cfg
|
|
from oslo_utils import uuidutils
|
|
import testtools
|
|
|
|
from neutron.agent.linux import ip_lib
|
|
from neutron.objects import trunk
|
|
from neutron.plugins.ml2.drivers.linuxbridge.agent import \
|
|
linuxbridge_neutron_agent
|
|
from neutron.services.trunk.drivers.linuxbridge.agent import trunk_plumber
|
|
from neutron.tests.functional.agent.linux import test_ip_lib
|
|
|
|
lba = linuxbridge_neutron_agent
|
|
|
|
|
|
class LinuxBridgeAgentTests(test_ip_lib.IpLibTestFramework):
|
|
|
|
def setUp(self):
|
|
super(LinuxBridgeAgentTests, self).setUp()
|
|
agent_rpc = ('neutron.agent.rpc.PluginApi')
|
|
mock.patch(agent_rpc).start()
|
|
mock.patch('neutron.agent.rpc.PluginReportStateAPI').start()
|
|
cfg.CONF.set_override('enable_vxlan', False, 'VXLAN')
|
|
|
|
def test_validate_interface_mappings(self):
|
|
mappings = {'physnet1': 'int1', 'physnet2': 'int2'}
|
|
with testtools.ExpectedException(SystemExit):
|
|
lba.LinuxBridgeManager({}, mappings)
|
|
self.manage_device(
|
|
self.generate_device_details()._replace(namespace=None,
|
|
name='int1'))
|
|
with testtools.ExpectedException(SystemExit):
|
|
lba.LinuxBridgeManager({}, mappings)
|
|
self.manage_device(
|
|
self.generate_device_details()._replace(namespace=None,
|
|
name='int2'))
|
|
lba.LinuxBridgeManager({}, mappings)
|
|
|
|
def test_validate_bridge_mappings(self):
|
|
mappings = {'physnet1': 'br-eth1'}
|
|
with testtools.ExpectedException(SystemExit):
|
|
lba.LinuxBridgeManager(mappings, {})
|
|
self.manage_device(
|
|
self.generate_device_details()._replace(namespace=None,
|
|
name='br-eth1'))
|
|
lba.LinuxBridgeManager(mappings, {})
|
|
|
|
def test_vlan_subinterfaces(self):
|
|
attr = self.generate_device_details()
|
|
device = self.manage_device(attr)
|
|
devname = device.name
|
|
plumber = trunk_plumber.Plumber(namespace=attr.namespace)
|
|
for i in range(20):
|
|
subname = 'vtest-%s' % i
|
|
plumber._create_vlan_subint(devname, subname, i)
|
|
# ensure no addresses were assigned (e.g. ipv6)
|
|
vlan_int = ip_lib.IPDevice(subname, namespace=attr.namespace)
|
|
self.assertFalse(vlan_int.addr.list())
|
|
children = plumber._get_vlan_children(devname)
|
|
expected = {('vtest-%s' % i, i) for i in range(20)}
|
|
self.assertEqual(expected, children)
|
|
|
|
# delete one
|
|
plumber._safe_delete_device('vtest-19')
|
|
children = plumber._get_vlan_children(devname)
|
|
expected = {('vtest-%s' % i, i) for i in range(19)}
|
|
self.assertEqual(expected, children)
|
|
# ensure they are removed by parent removal
|
|
self._safe_delete_device(device)
|
|
self.assertFalse(plumber._get_vlan_children(devname))
|
|
|
|
def test_vlan_QinQ_subinterfaces(self):
|
|
# the trunk model does not support this right now, but this is to
|
|
# ensure the plumber on the agent side doesn't explode in their
|
|
# presence in case an operator does something fancy or we have a
|
|
# race where a trunk's parent port is converted to a subport while
|
|
# the agent is offline.
|
|
attr = self.generate_device_details()
|
|
device = self.manage_device(attr)
|
|
devname = device.name
|
|
plumber = trunk_plumber.Plumber(namespace=attr.namespace)
|
|
for i in range(20):
|
|
plumber._create_vlan_subint(devname, 'vtest-%s' % i, i)
|
|
plumber._create_vlan_subint('vtest-%s' % i, 'qinq-%s' % i, 2)
|
|
top_level = {('vtest-%s' % i, i) for i in range(20)}
|
|
for i in range(20):
|
|
# as we iterate, we delete a vlan from each dev and ensure it
|
|
# didn't break the top-level vlans
|
|
self.assertEqual({('qinq-%s' % i, 2)},
|
|
plumber._get_vlan_children('vtest-%s' % i))
|
|
plumber._safe_delete_device('qinq-%s' % i)
|
|
self.assertEqual(set(), plumber._get_vlan_children('vtest-%i' % i))
|
|
self.assertEqual(top_level, plumber._get_vlan_children(devname))
|
|
|
|
def test_ensure_trunk_subports(self):
|
|
attr = self.generate_device_details()
|
|
device = self.manage_device(attr)
|
|
devname = device.name
|
|
plumber = trunk_plumber.Plumber(namespace=attr.namespace)
|
|
plumber._trunk_device_name = lambda x: devname
|
|
trunk_obj = self._gen_trunk()
|
|
plumber.ensure_trunk_subports(trunk_obj)
|
|
# ensure no mutation the second time
|
|
with mock.patch.object(plumber, '_safe_delete_device',
|
|
side_effect=RuntimeError()):
|
|
plumber.ensure_trunk_subports(trunk_obj)
|
|
|
|
while trunk_obj.sub_ports:
|
|
# drain down the sub-ports and make sure it keeps
|
|
# them equal
|
|
trunk_obj.sub_ports.pop()
|
|
plumber.ensure_trunk_subports(trunk_obj)
|
|
expected = {(plumber._get_tap_device_name(sp.port_id),
|
|
sp.segmentation_id)
|
|
for sp in trunk_obj.sub_ports}
|
|
wired = plumber._get_vlan_children(devname)
|
|
self.assertEqual(expected, wired)
|
|
|
|
def _gen_trunk(self):
|
|
trunk_obj = trunk.Trunk(id=uuidutils.generate_uuid(),
|
|
port_id=uuidutils.generate_uuid(),
|
|
project_id=uuidutils.generate_uuid())
|
|
subports = [trunk.SubPort(id=uuidutils.generate_uuid(),
|
|
port_id=uuidutils.generate_uuid(),
|
|
segmentation_type='vlan',
|
|
trunk_id=trunk_obj.id,
|
|
segmentation_id=i)
|
|
for i in range(20, 40)]
|
|
trunk_obj.sub_ports = subports
|
|
return trunk_obj
|