Move nova-lxd to use os-vif.
This patch introduces a new vif driver that implements only plug/unplug. Those methods merely act as a thin layer over the os-vif functionality, which requires some adaptation between nova instances/vifs and os-vif instances/vifs. The rest of the functionality that was once part of the vif driver has been moved to functions, as there was no need to make them member methods (i.e. they never needed `self`). Rather than using the dynamic function call via string interpolation pattern (which was taken from the libvirt driver, but is still fragile). Instead, I opted for an explicit map for config generation. This patch has 100% test coverage. The vif library was in dire need of attention, and as a result of the os-vif transition, it got it. Change-Id: I175f4df9b58b038b594a40c16076b06f2521bcfc
This commit is contained in:
parent
ccae5dcec4
commit
f434b721cd
|
@ -0,0 +1,158 @@
|
|||
# Copyright 2016 Canonical Ltd
|
||||
# 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 nova import context
|
||||
from nova import exception
|
||||
from nova.network import model as network_model
|
||||
from nova import test
|
||||
from nova.tests.unit import fake_instance
|
||||
from nova.virt.lxd import vif
|
||||
|
||||
GATEWAY = network_model.IP(address='101.168.1.1', type='gateway')
|
||||
DNS_BRIDGE = network_model.IP(address='8.8.8.8', type=None)
|
||||
SUBNET = network_model.Subnet(
|
||||
cidr='101.168.1.0/24', dns=[DNS_BRIDGE], gateway=GATEWAY,
|
||||
routes=None, dhcp_server='191.168.1.1')
|
||||
NETWORK = network_model.Network(
|
||||
id='network-id-xxx-yyy-zzz', bridge='br0', label=None,
|
||||
subnets=[SUBNET], bridge_interface=None, vlan=99, mtu=1000)
|
||||
VIF = network_model.VIF(
|
||||
id='0123456789abcdef', address='ca:fe:de:ad:be:ef',
|
||||
network=NETWORK, type=network_model.VIF_TYPE_OVS,
|
||||
devname='tap-012-345-678', ovs_interfaceid='9abc-def-000')
|
||||
INSTANCE = fake_instance.fake_instance_obj(
|
||||
context.get_admin_context(), name='test')
|
||||
|
||||
|
||||
class GetVifDevnameTest(test.NoDBTestCase):
|
||||
"""Tests for get_vif_devname."""
|
||||
|
||||
def test_get_vif_devname_devname_exists(self):
|
||||
an_vif = {
|
||||
'id': '0123456789abcdef',
|
||||
'devname': 'oth1',
|
||||
}
|
||||
|
||||
devname = vif.get_vif_devname(an_vif)
|
||||
|
||||
self.assertEqual('oth1', devname)
|
||||
|
||||
def test_get_vif_devname_devname_nonexistent(self):
|
||||
an_vif = {
|
||||
'id': '0123456789abcdef',
|
||||
}
|
||||
|
||||
devname = vif.get_vif_devname(an_vif)
|
||||
|
||||
self.assertEqual('nic0123456789a', devname)
|
||||
|
||||
|
||||
class GetConfigTest(test.NoDBTestCase):
|
||||
"""Tests for get_config."""
|
||||
|
||||
def setUp(self):
|
||||
super(GetConfigTest, self).setUp()
|
||||
self.CONF_patcher = mock.patch('nova.virt.lxd.vif.conf.CONF')
|
||||
self.CONF = self.CONF_patcher.start()
|
||||
self.CONF.firewall_driver = 'nova.virt.firewall.NoopFirewallDriver'
|
||||
|
||||
def tearDown(self):
|
||||
super(GetConfigTest, self).tearDown()
|
||||
self.CONF_patcher.stop()
|
||||
|
||||
def test_get_config_bad_vif_type(self):
|
||||
"""Unsupported vif types raise an exception."""
|
||||
an_vif = network_model.VIF(
|
||||
id='0123456789abcdef', address='ca:fe:de:ad:be:ef',
|
||||
network=NETWORK, type='invalid',
|
||||
devname='tap-012-345-678', ovs_interfaceid='9abc-def-000')
|
||||
|
||||
self.assertRaises(
|
||||
exception.NovaException, vif.get_config, an_vif)
|
||||
|
||||
def test_get_config_bridge(self):
|
||||
expected = {'bridge': 'br0', 'mac_address': 'ca:fe:de:ad:be:ef'}
|
||||
an_vif = network_model.VIF(
|
||||
id='0123456789abcdef', address='ca:fe:de:ad:be:ef',
|
||||
network=NETWORK, type='bridge',
|
||||
devname='tap-012-345-678', ovs_interfaceid='9abc-def-000')
|
||||
|
||||
config = vif.get_config(an_vif)
|
||||
|
||||
self.assertEqual(expected, config)
|
||||
|
||||
def test_get_config_ovs_bridge(self):
|
||||
expected = {
|
||||
'bridge': 'br0', 'mac_address': 'ca:fe:de:ad:be:ef'}
|
||||
an_vif = network_model.VIF(
|
||||
id='0123456789abcdef', address='ca:fe:de:ad:be:ef',
|
||||
network=NETWORK, type='ovs',
|
||||
devname='tap-012-345-678', ovs_interfaceid='9abc-def-000')
|
||||
|
||||
config = vif.get_config(an_vif)
|
||||
|
||||
self.assertEqual(expected, config)
|
||||
|
||||
def test_get_config_ovs_hybrid(self):
|
||||
self.CONF.firewall_driver = 'AnFirewallDriver'
|
||||
|
||||
expected = {
|
||||
'bridge': 'qbr0123456789a', 'mac_address': 'ca:fe:de:ad:be:ef'}
|
||||
an_vif = network_model.VIF(
|
||||
id='0123456789abcdef', address='ca:fe:de:ad:be:ef',
|
||||
network=NETWORK, type='ovs',
|
||||
devname='tap-012-345-678', ovs_interfaceid='9abc-def-000')
|
||||
|
||||
config = vif.get_config(an_vif)
|
||||
|
||||
self.assertEqual(expected, config)
|
||||
|
||||
def test_get_config_tap(self):
|
||||
expected = {'mac_address': 'ca:fe:de:ad:be:ef'}
|
||||
an_vif = network_model.VIF(
|
||||
id='0123456789abcdef', address='ca:fe:de:ad:be:ef',
|
||||
network=NETWORK, type='tap',
|
||||
devname='tap-012-345-678', ovs_interfaceid='9abc-def-000')
|
||||
|
||||
config = vif.get_config(an_vif)
|
||||
|
||||
self.assertEqual(expected, config)
|
||||
|
||||
|
||||
class LXDGenericVifDriverTest(test.NoDBTestCase):
|
||||
"""Tests for LXDGenericVifDriver."""
|
||||
|
||||
def setUp(self):
|
||||
super(LXDGenericVifDriverTest, self).setUp()
|
||||
self.vif_driver = vif.LXDGenericVifDriver()
|
||||
|
||||
@mock.patch('nova.virt.lxd.vif.os_vif')
|
||||
def test_plug(self, os_vif):
|
||||
self.vif_driver.plug(INSTANCE, VIF)
|
||||
|
||||
self.assertEqual(
|
||||
'tap-012-345-678', os_vif.plug.call_args[0][0].vif_name)
|
||||
self.assertEqual(
|
||||
'instance-00000001', os_vif.plug.call_args[0][1].name)
|
||||
|
||||
@mock.patch('nova.virt.lxd.vif.os_vif')
|
||||
def test_unplug(self, os_vif):
|
||||
self.vif_driver.unplug(INSTANCE, VIF)
|
||||
|
||||
self.assertEqual(
|
||||
'tap-012-345-678', os_vif.unplug.call_args[0][0].vif_name)
|
||||
self.assertEqual(
|
||||
'instance-00000001', os_vif.unplug.call_args[0][1].name)
|
|
@ -1,164 +0,0 @@
|
|||
# Copyright 2015 Canonical Ltd
|
||||
# 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 copy
|
||||
|
||||
import ddt
|
||||
import mock
|
||||
from oslo_concurrency import processutils
|
||||
|
||||
from nova import exception
|
||||
from nova.network import model as network_model
|
||||
from nova import test
|
||||
|
||||
from nova.virt.lxd import vif
|
||||
import stubs
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class LXDTestNetworkDriver(test.NoDBTestCase):
|
||||
|
||||
vif_data = {
|
||||
'id': '0123456789abcdef',
|
||||
'type': network_model.VIF_TYPE_OVS,
|
||||
'address': '00:11:22:33:44:55',
|
||||
'network': {
|
||||
'bridge': 'fakebr'}}
|
||||
|
||||
def setUp(self):
|
||||
super(LXDTestNetworkDriver, self).setUp()
|
||||
|
||||
self.vif_driver = vif.LXDGenericDriver()
|
||||
|
||||
mn = mock.Mock()
|
||||
net_patcher = mock.patch.object(vif, 'linux_net', mn)
|
||||
net_patcher.start()
|
||||
self.addCleanup(net_patcher.stop)
|
||||
|
||||
me = mock.Mock()
|
||||
net_patcher = mock.patch.object(vif.utils, 'execute', me)
|
||||
net_patcher.start()
|
||||
self.addCleanup(net_patcher.stop)
|
||||
|
||||
self.mgr = mock.Mock()
|
||||
self.mgr.attach_mock(mn, 'net')
|
||||
self.mgr.attach_mock(me, 'ex')
|
||||
|
||||
def test_nonetype(self):
|
||||
instance = stubs.MockInstance()
|
||||
vif_data = {'type': None}
|
||||
self.assertRaises(
|
||||
exception.NovaException,
|
||||
self.vif_driver.plug,
|
||||
instance, vif_data)
|
||||
|
||||
def test_get_config_ovs(self):
|
||||
instance = stubs._fake_instance()
|
||||
vif_data = copy.deepcopy(self.vif_data)
|
||||
|
||||
vif_type = self.vif_driver.get_config(instance, vif_data)
|
||||
self.assertEqual(vif_type, {'bridge': 'qbr0123456789a',
|
||||
'mac_address': '00:11:22:33:44:55'})
|
||||
|
||||
def test_get_config_bridge(self):
|
||||
instance = stubs._fake_instance()
|
||||
vif_data = copy.deepcopy(self.vif_data)
|
||||
|
||||
vif_type = self.vif_driver.get_config(instance, vif_data)
|
||||
self.assertEqual(vif_type, {'bridge': 'qbr0123456789a',
|
||||
'mac_address': '00:11:22:33:44:55'})
|
||||
|
||||
@stubs.annotated_data(
|
||||
('id', {}, [True, True]),
|
||||
('ovs-id', {'ovs_interfaceid': '123456789abcdef0'}, [True, True]),
|
||||
('no-bridge', {}, [False, True]),
|
||||
('no-v2', {}, [True, False]),
|
||||
('no-bridge-or-v2', {}, [False, False]),
|
||||
)
|
||||
def test_plug(self, tag, vif_data, exists):
|
||||
instance = stubs.MockInstance()
|
||||
vif_data = copy.deepcopy(self.vif_data)
|
||||
vif_data.update(vif_data)
|
||||
self.mgr.net.device_exists.side_effect = exists
|
||||
self.assertEqual(
|
||||
None,
|
||||
self.vif_driver.plug(instance, vif_data))
|
||||
calls = [
|
||||
mock.call.net.device_exists('qbr0123456789a'),
|
||||
mock.call.net.device_exists('qvo0123456789a')
|
||||
]
|
||||
if not exists[0]:
|
||||
calls[1:1] = [
|
||||
mock.call.ex(
|
||||
'brctl', 'addbr', 'qbr0123456789a', run_as_root=True),
|
||||
mock.call.ex(
|
||||
'brctl', 'setfd', 'qbr0123456789a', 0, run_as_root=True),
|
||||
mock.call.ex('brctl', 'stp', 'qbr0123456789a', 'off',
|
||||
run_as_root=True),
|
||||
mock.call.ex('tee',
|
||||
'/sys/class/net/qbr0123456789a/'
|
||||
'bridge/multicast_snooping',
|
||||
process_input='0', run_as_root=True,
|
||||
check_exit_code=[0, 1]),
|
||||
]
|
||||
if not exists[1]:
|
||||
calls.extend([
|
||||
mock.call.net._create_veth_pair('qvb0123456789a',
|
||||
'qvo0123456789a'),
|
||||
mock.call.ex('ip', 'link', 'set', 'qbr0123456789a', 'up',
|
||||
run_as_root=True),
|
||||
mock.call.ex('brctl', 'addif', 'qbr0123456789a',
|
||||
'qvb0123456789a', run_as_root=True)])
|
||||
calls.append(mock.call.net.create_ovs_vif_port(
|
||||
'fakebr', 'qvo0123456789a', '0123456789abcdef',
|
||||
'00:11:22:33:44:55', 'fake-uuid'))
|
||||
self.assertEqual(calls, self.mgr.method_calls)
|
||||
|
||||
def test_unplug_fail(self):
|
||||
instance = stubs.MockInstance()
|
||||
vif_data = copy.deepcopy(self.vif_data)
|
||||
self.mgr.net.device_exists.side_effect = (
|
||||
processutils.ProcessExecutionError)
|
||||
self.assertEqual(
|
||||
None,
|
||||
self.vif_driver.unplug(instance, vif_data))
|
||||
|
||||
@stubs.annotated_data(
|
||||
('id', {}, [True, True]),
|
||||
('ovs-id', {'ovs_interfaceid': '123456789abcdef0'}, [True, True]),
|
||||
('no-bridge', {}, [False, True]),
|
||||
('no-v2', {}, [True, False]),
|
||||
('no-bridge-or-v2', {}, [False, False]),
|
||||
)
|
||||
def test_unplug(self, tag, vif_data, exists):
|
||||
instance = stubs.MockInstance()
|
||||
vif = copy.deepcopy(self.vif_data)
|
||||
self.mgr.net.device_exists.side_effect = exists
|
||||
self.assertEqual(
|
||||
None,
|
||||
self.vif_driver.unplug(instance, vif))
|
||||
|
||||
calls = [mock.call.net.device_exists('qbr0123456789a')]
|
||||
if exists[0]:
|
||||
calls[1:1] = [
|
||||
mock.call.ex('brctl', 'delif', 'qbr0123456789a',
|
||||
'qvb0123456789a', run_as_root=True),
|
||||
mock.call.ex('ip', 'link', 'set', 'qbr0123456789a',
|
||||
'down', run_as_root=True),
|
||||
mock.call.ex('brctl', 'delbr', 'qbr0123456789a',
|
||||
run_as_root=True),
|
||||
mock.call.net.delete_ovs_vif_port('fakebr', 'qvo0123456789a')
|
||||
]
|
||||
self.assertEqual(calls, self.mgr.method_calls)
|
|
@ -222,7 +222,7 @@ class LXDDriver(driver.ComputeDriver):
|
|||
self.client = None # Initialized by init_host
|
||||
self.host = NOVA_CONF.host
|
||||
self.network_api = network.API()
|
||||
self.vif_driver = lxd_vif.LXDGenericDriver()
|
||||
self.vif_driver = lxd_vif.LXDGenericVifDriver()
|
||||
self.firewall_driver = firewall.load_driver(
|
||||
default='nova.virt.firewall.NoopFirewallDriver')
|
||||
|
||||
|
@ -596,7 +596,7 @@ class LXDDriver(driver.ComputeDriver):
|
|||
interfaces.append(key)
|
||||
net_device = 'eth{}'.format(len(interfaces))
|
||||
|
||||
network_config = self.vif_driver.get_config(instance, vif)
|
||||
network_config = lxd_vif.get_config(vif)
|
||||
if 'bridge' in network_config:
|
||||
config_update = {
|
||||
net_device: {
|
||||
|
@ -1603,7 +1603,7 @@ class LXDDriver(driver.ComputeDriver):
|
|||
return
|
||||
|
||||
for vifaddr in network_info:
|
||||
cfg = self.vif_driver.get_config(instance, vifaddr)
|
||||
cfg = lxd_vif.get_config(vifaddr)
|
||||
if 'bridge' in cfg:
|
||||
key = str(cfg['bridge'])
|
||||
network_devices[key] = {
|
||||
|
@ -1619,7 +1619,7 @@ class LXDDriver(driver.ComputeDriver):
|
|||
'hwaddr': str(cfg['mac_address']),
|
||||
'type': 'nic'
|
||||
}
|
||||
host_device = self.vif_driver.get_vif_devname(vifaddr)
|
||||
host_device = lxd_vif.get_vif_devname(vifaddr)
|
||||
if host_device:
|
||||
network_devices[key]['host_name'] = host_device
|
||||
# Set network device quotas
|
||||
|
|
|
@ -11,223 +11,75 @@
|
|||
# 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 oslo_concurrency import processutils
|
||||
from oslo_log import log as logging
|
||||
|
||||
import nova.conf
|
||||
from nova import conf
|
||||
from nova import exception
|
||||
from nova import i18n
|
||||
from nova.network import linux_net
|
||||
from nova.network import model as network_model
|
||||
from nova import utils
|
||||
from nova.network import os_vif_util
|
||||
|
||||
_ = i18n._
|
||||
_LE = i18n._LE
|
||||
|
||||
CONF = nova.conf.CONF
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
import os_vif
|
||||
|
||||
|
||||
class LXDGenericDriver(object):
|
||||
def get_vif_devname(vif):
|
||||
"""Get device name for a given vif."""
|
||||
if 'devname' in vif:
|
||||
return vif['devname']
|
||||
return ("nic" + vif['id'])[:network_model.NIC_NAME_LEN]
|
||||
|
||||
def get_vif_devname(self, vif):
|
||||
if 'devname' in vif:
|
||||
return vif['devname']
|
||||
return ("nic" + vif['id'])[:network_model.NIC_NAME_LEN]
|
||||
|
||||
def get_vif_devname_with_prefix(self, vif, prefix):
|
||||
devname = self.get_vif_devname(vif)
|
||||
return prefix + devname[3:]
|
||||
def _get_bridge_config(vif):
|
||||
return {
|
||||
'bridge': vif['network']['bridge'],
|
||||
'mac_address': vif['address']}
|
||||
|
||||
def get_bridge_name(self, vif):
|
||||
return vif['network']['bridge']
|
||||
|
||||
def get_ovs_interfaceid(self, vif):
|
||||
return vif.get('ovs_interfaceid') or vif['id']
|
||||
def _get_ovs_config(vif):
|
||||
if (conf.CONF.firewall_driver != 'nova.virt.firewall.NoopFirewallDriver' or
|
||||
vif.is_hybrid_plug_enabled()):
|
||||
return {
|
||||
'bridge': ('qbr{}'.format(vif['id']))[:network_model.NIC_NAME_LEN],
|
||||
'mac_address': vif['address']}
|
||||
else:
|
||||
return {
|
||||
'bridge': vif['network']['bridge'],
|
||||
'mac_address': vif['address']}
|
||||
|
||||
def get_br_name(self, iface_id):
|
||||
return ("qbr" + iface_id)[:network_model.NIC_NAME_LEN]
|
||||
|
||||
def get_veth_pair_names(self, iface_id):
|
||||
return (("qvb%s" % iface_id)[:network_model.NIC_NAME_LEN],
|
||||
("qvo%s" % iface_id)[:network_model.NIC_NAME_LEN])
|
||||
def _get_tap_config(vif):
|
||||
return {'mac_address': vif['address']}
|
||||
|
||||
def get_firewall_required(self, vif):
|
||||
if CONF.firewall_driver != "nova.virt.firewall.NoopFirewallDriver":
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_config(self, instance, vif):
|
||||
vif_type = vif['type']
|
||||
CONFIG_GENERATORS = {
|
||||
'bridge': _get_bridge_config,
|
||||
'ovs': _get_ovs_config,
|
||||
'tap': _get_tap_config,
|
||||
}
|
||||
|
||||
LOG.debug('vif_type=%(vif_type)s instance=%(instance)s '
|
||||
'vif=%(vif)s',
|
||||
{'vif_type': vif_type, 'instance': instance,
|
||||
'vif': vif})
|
||||
|
||||
if vif_type is None:
|
||||
raise exception.NovaException(
|
||||
_("vif_type parameter must be present "
|
||||
"for this vif_driver implementation"))
|
||||
func = getattr(self, 'get_config_%s' % vif_type, None)
|
||||
if not func:
|
||||
raise exception.NovaException(
|
||||
_("Unexpected vif_type=%s") % vif_type)
|
||||
return func(instance, vif)
|
||||
def get_config(vif):
|
||||
"""Get LXD specific config for a vif."""
|
||||
vif_type = vif['type']
|
||||
|
||||
def get_config_bridge(self, instance, vif):
|
||||
conf = {'bridge': self.get_bridge_name(vif),
|
||||
'mac_address': vif['address']}
|
||||
return conf
|
||||
try:
|
||||
return CONFIG_GENERATORS[vif_type](vif)
|
||||
except KeyError:
|
||||
raise exception.NovaException(
|
||||
'Unsupported vif type: {}'.format(vif_type))
|
||||
|
||||
def get_config_ovs_hybrid(self, instance, vif):
|
||||
conf = {'bridge': self.get_br_name(vif['id']),
|
||||
'mac_address': vif['address']}
|
||||
|
||||
return conf
|
||||
class LXDGenericVifDriver(object):
|
||||
"""Generic VIF driver for LXD networking."""
|
||||
|
||||
def get_config_ovs_bridge(self, instance, vif):
|
||||
conf = {'bridge': self.get_bridge_name(vif),
|
||||
'mac_address': vif['address']}
|
||||
|
||||
return conf
|
||||
|
||||
def get_config_ovs(self, instance, vif):
|
||||
if self.get_firewall_required(vif) or vif.is_hybrid_plug_enabled():
|
||||
return self.get_config_ovs_hybrid(instance, vif)
|
||||
else:
|
||||
return self.get_config_ovs_bridge(instance, vif)
|
||||
|
||||
def get_config_tap(self, instance, vif):
|
||||
conf = {'mac_address': vif['address']}
|
||||
return conf
|
||||
def __init__(self):
|
||||
os_vif.initialize()
|
||||
|
||||
def plug(self, instance, vif):
|
||||
vif_type = vif['type']
|
||||
instance_info = os_vif_util.nova_to_osvif_instance(instance)
|
||||
vif_obj = os_vif_util.nova_to_osvif_vif(vif)
|
||||
|
||||
LOG.debug('vif_type=%(vif_type)s instance=%(instance)s '
|
||||
'vif=%(vif)s',
|
||||
{'vif_type': vif_type, 'instance': instance,
|
||||
'vif': vif})
|
||||
|
||||
if vif_type is None:
|
||||
raise exception.NovaException(
|
||||
_("vif_type parameter must be present "
|
||||
"for this vif_driver implementation"))
|
||||
func = getattr(self, 'plug_%s' % vif_type, None)
|
||||
if not func:
|
||||
raise exception.NovaException(
|
||||
_("Unexpected vif_type=%s") % vif_type)
|
||||
return func(instance, vif)
|
||||
|
||||
def plug_bridge(self, instance, vif):
|
||||
network = vif['network']
|
||||
if (not network.get_meta('multi_host', False) and
|
||||
network.get_meta('should_create_bridge', False)):
|
||||
if network.get_meta('should_create_vlan', False):
|
||||
iface = (CONF.vlan_interface or
|
||||
network.get_meta('bridge_interface'))
|
||||
LOG.debug('Ensuring vlan %(vlan)s and bridge %(bridge)s',
|
||||
{'vlan': network.get_meta('vlan'),
|
||||
'bridge': self.get_bridge_name(vif)},
|
||||
instance=instance)
|
||||
linux_net.LinuxBridgeInterfaceDriver.ensure_vlan_bridge(
|
||||
network.get_meta('vlan'),
|
||||
self.get_bridge_name(vif), iface)
|
||||
else:
|
||||
iface = (CONF.flat_interface or
|
||||
network.get_meta('bridge_interface'))
|
||||
LOG.debug("Ensuring bridge %s",
|
||||
self.get_bridge_name(vif), instance=instance)
|
||||
linux_net.LinuxBridgeInterfaceDriver.ensure_bridge(
|
||||
self.get_bridge_name(vif), iface)
|
||||
|
||||
def plug_ovs(self, instance, vif):
|
||||
if self.get_firewall_required(vif) or vif.is_hybrid_plug_enabled():
|
||||
self.plug_ovs_hybrid(instance, vif)
|
||||
else:
|
||||
self.plug_ovs_bridge(instance, vif)
|
||||
|
||||
def plug_ovs_bridge(self, instance, vif):
|
||||
pass
|
||||
|
||||
def plug_ovs_hybrid(self, instance, vif):
|
||||
iface_id = self.get_ovs_interfaceid(vif)
|
||||
br_name = self.get_br_name(vif['id'])
|
||||
v1_name, v2_name = self.get_veth_pair_names(vif['id'])
|
||||
|
||||
if not linux_net.device_exists(br_name):
|
||||
utils.execute('brctl', 'addbr', br_name, run_as_root=True)
|
||||
utils.execute('brctl', 'setfd', br_name, 0, run_as_root=True)
|
||||
utils.execute('brctl', 'stp', br_name, 'off', run_as_root=True)
|
||||
utils.execute('tee',
|
||||
('/sys/class/net/%s/bridge/multicast_snooping' %
|
||||
br_name),
|
||||
process_input='0',
|
||||
run_as_root=True,
|
||||
check_exit_code=[0, 1])
|
||||
|
||||
if not linux_net.device_exists(v2_name):
|
||||
linux_net._create_veth_pair(v1_name, v2_name)
|
||||
utils.execute('ip', 'link', 'set', br_name, 'up', run_as_root=True)
|
||||
utils.execute('brctl', 'addif', br_name, v1_name, run_as_root=True)
|
||||
linux_net.create_ovs_vif_port(self.get_bridge_name(vif),
|
||||
v2_name, iface_id,
|
||||
vif['address'], instance.name)
|
||||
|
||||
def plug_tap(self, instance, vif):
|
||||
pass
|
||||
os_vif.plug(vif_obj, instance_info)
|
||||
|
||||
def unplug(self, instance, vif):
|
||||
vif_type = vif['type']
|
||||
instance_info = os_vif_util.nova_to_osvif_instance(instance)
|
||||
vif_obj = os_vif_util.nova_to_osvif_vif(vif)
|
||||
|
||||
LOG.debug('vif_type=%(vif_type)s instance=%(instance)s '
|
||||
'vif=%(vif)s',
|
||||
{'vif_type': vif_type, 'instance': instance,
|
||||
'vif': vif})
|
||||
|
||||
if vif_type is None:
|
||||
raise exception.NovaException(
|
||||
_("vif_type parameter must be present "
|
||||
"for this vif_driver implementation"))
|
||||
func = getattr(self, 'unplug_%s' % vif_type, None)
|
||||
if not func:
|
||||
raise exception.NovaException(
|
||||
_("Unexpected vif_type=%s") % vif_type)
|
||||
return func(instance, vif)
|
||||
|
||||
def unplug_ovs(self, instance, vif):
|
||||
if self.get_firewall_required(vif) or vif.is_hybrid_plug_enabled():
|
||||
self.unplug_ovs_hybrid(instance, vif)
|
||||
else:
|
||||
self.unplug_ovs_bridge(instance, vif)
|
||||
|
||||
def unplug_ovs_hybrid(self, instance, vif):
|
||||
try:
|
||||
br_name = self.get_br_name(vif['id'])
|
||||
v1_name, v2_name = self.get_veth_pair_names(vif['id'])
|
||||
|
||||
if linux_net.device_exists(br_name):
|
||||
utils.execute('brctl', 'delif', br_name, v1_name,
|
||||
run_as_root=True)
|
||||
utils.execute('ip', 'link', 'set', br_name, 'down',
|
||||
run_as_root=True)
|
||||
utils.execute('brctl', 'delbr', br_name,
|
||||
run_as_root=True)
|
||||
|
||||
linux_net.delete_ovs_vif_port(self.get_bridge_name(vif),
|
||||
v2_name)
|
||||
except processutils.ProcessExecutionError:
|
||||
LOG.exception(_LE("Failed while unplugging vif"),
|
||||
instance=instance)
|
||||
|
||||
def unplug_ovs_bridge(self, instance, vif):
|
||||
pass
|
||||
|
||||
def unplug_bridge(self, instance, vif):
|
||||
pass
|
||||
|
||||
def unplug_tap(self, instance, vif):
|
||||
pass
|
||||
os_vif.unplug(vif_obj, instance_info)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
pbr>=1.8 # Apache-2.0
|
||||
os-brick>=1.8.0 # Apache-2.0
|
||||
os-vif>=1.3.0 # Apache-2.0
|
||||
oslo.config!=3.18.0,>=3.14.0 # Apache-2.0
|
||||
oslo.concurrency>=3.8.0 # Apache-2.0
|
||||
oslo.utils>=3.18.0 # Apache-2.0
|
||||
|
|
Loading…
Reference in New Issue