Merge "libvirt vif-plugging fixes. Fixes bug 939252 , bug 939254"
This commit is contained in:
159
nova/tests/test_libvirt_vif.py
Normal file
159
nova/tests/test_libvirt_vif.py
Normal file
@@ -0,0 +1,159 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2012 Nicira, 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 xml.etree import ElementTree
|
||||
|
||||
from nova import flags
|
||||
from nova import test
|
||||
from nova import utils
|
||||
from nova.virt import firewall
|
||||
from nova.virt import vif
|
||||
from nova.virt.libvirt import connection
|
||||
from nova.virt.libvirt.vif import LibvirtBridgeDriver, \
|
||||
LibvirtOpenVswitchDriver, LibvirtOpenVswitchVirtualPortDriver
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
|
||||
class LibvirtVifTestCase(test.TestCase):
|
||||
|
||||
net = {
|
||||
'cidr': '101.168.1.0/24',
|
||||
'cidr_v6': '101:1db9::/64',
|
||||
'gateway_v6': '101:1db9::1',
|
||||
'netmask_v6': '64',
|
||||
'netmask': '255.255.255.0',
|
||||
'bridge': 'br0',
|
||||
'bridge_interface': 'eth0',
|
||||
'vlan': 99,
|
||||
'gateway': '101.168.1.1',
|
||||
'broadcast': '101.168.1.255',
|
||||
'dns1': '8.8.8.8'
|
||||
}
|
||||
|
||||
mapping = {
|
||||
'mac': 'ca:fe:de:ad:be:ef',
|
||||
'gateway_v6': net['gateway_v6'],
|
||||
'ips': [{'ip': '101.168.1.9'}],
|
||||
'dhcp_server': '191.168.1.1',
|
||||
'vif_uuid': 'vif-xxx-yyy-zzz'
|
||||
}
|
||||
|
||||
instance = {
|
||||
'uuid': 'instance-uuid'
|
||||
}
|
||||
|
||||
def setUp(self):
|
||||
super(LibvirtVifTestCase, self).setUp()
|
||||
self.flags(allow_same_net_traffic=True)
|
||||
self.executes = []
|
||||
|
||||
def fake_execute(*cmd, **kwargs):
|
||||
self.executes.append(cmd)
|
||||
return None, None
|
||||
|
||||
self.stubs.Set(utils, 'execute', fake_execute)
|
||||
t = __import__('Cheetah.Template', globals(), locals(),
|
||||
['Template'], -1)
|
||||
self.Template = t.Template
|
||||
xml_file = open(FLAGS.libvirt_xml_template)
|
||||
self.xml_template = xml_file.read()
|
||||
|
||||
def _create_xml_info(self, vif_type, nics):
|
||||
return {
|
||||
'type': 'qemu',
|
||||
'name': 'fake-name',
|
||||
'uuid': 'fake-uuid',
|
||||
'memory_kb': 100 * 1024,
|
||||
'basepath': 'foobar',
|
||||
'vcpus': 4,
|
||||
'rescue': False,
|
||||
'disk_prefix': '/dev/sda',
|
||||
'driver_type': 'raw',
|
||||
'root_device_type': 'disk',
|
||||
'vif_type': vif_type,
|
||||
'nics': nics,
|
||||
'ebs_root': True,
|
||||
'ephemeral_device': False,
|
||||
'volumes': [],
|
||||
'use_virtio_for_bridges': False,
|
||||
'ephemerals': []}
|
||||
|
||||
def _get_instance_xml(self, driver, vif_type):
|
||||
nic_dict = driver.plug(self.instance, self.net, self.mapping)
|
||||
xml_info = self._create_xml_info(vif_type, [nic_dict])
|
||||
xml = str(self.Template(self.xml_template, searchList=[xml_info]))
|
||||
return xml
|
||||
|
||||
def test_bridge_driver(self):
|
||||
d = LibvirtBridgeDriver()
|
||||
xml = self._get_instance_xml(d, 'bridge')
|
||||
|
||||
doc = ElementTree.fromstring(xml)
|
||||
ret = doc.findall('./devices/interface')
|
||||
self.assertEqual(len(ret), 1)
|
||||
node = ret[0]
|
||||
self.assertEqual(node.get("type"), "bridge")
|
||||
br_name = node.find("source").get("bridge")
|
||||
self.assertEqual(br_name, self.net['bridge'])
|
||||
mac = node.find("mac").get("address")
|
||||
self.assertEqual(mac, self.mapping['mac'])
|
||||
|
||||
d.unplug(None, self.net, self.mapping)
|
||||
|
||||
def test_ovs_ethernet_driver(self):
|
||||
d = LibvirtOpenVswitchDriver()
|
||||
xml = self._get_instance_xml(d, 'ethernet')
|
||||
|
||||
doc = ElementTree.fromstring(xml)
|
||||
ret = doc.findall('./devices/interface')
|
||||
self.assertEqual(len(ret), 1)
|
||||
node = ret[0]
|
||||
self.assertEqual(node.get("type"), "ethernet")
|
||||
dev_name = node.find("target").get("dev")
|
||||
self.assertTrue(dev_name.startswith("tap"))
|
||||
mac = node.find("mac").get("address")
|
||||
self.assertEqual(mac, self.mapping['mac'])
|
||||
script = node.find("script").get("path")
|
||||
self.assertEquals(script, "")
|
||||
|
||||
d.unplug(None, self.net, self.mapping)
|
||||
|
||||
def test_ovs_virtualport_driver(self):
|
||||
d = LibvirtOpenVswitchVirtualPortDriver()
|
||||
xml = self._get_instance_xml(d, 'ovs_virtualport')
|
||||
|
||||
doc = ElementTree.fromstring(xml)
|
||||
ret = doc.findall('./devices/interface')
|
||||
self.assertEqual(len(ret), 1)
|
||||
node = ret[0]
|
||||
self.assertEqual(node.get("type"), "bridge")
|
||||
|
||||
br_name = node.find("source").get("bridge")
|
||||
self.assertEqual(br_name, FLAGS.libvirt_ovs_bridge)
|
||||
mac = node.find("mac").get("address")
|
||||
self.assertEqual(mac, self.mapping['mac'])
|
||||
vp = node.find("virtualport")
|
||||
self.assertEqual(vp.get("type"), "openvswitch")
|
||||
iface_id_found = False
|
||||
for p_elem in vp.findall("parameters"):
|
||||
iface_id = p_elem.get("interfaceid", None)
|
||||
if iface_id:
|
||||
self.assertEqual(iface_id, self.mapping['vif_uuid'])
|
||||
iface_id_found = True
|
||||
|
||||
self.assertTrue(iface_id_found)
|
||||
d.unplug(None, self.net, self.mapping)
|
@@ -130,6 +130,14 @@
|
||||
</virtualport>
|
||||
<model type='virtio'/>
|
||||
</interface>
|
||||
#else if $vif_type == 'ovs_virtualport'
|
||||
<interface type='bridge'>
|
||||
<source bridge='${nic.bridge_name}'/>
|
||||
<mac address='${nic.mac_address}'/>
|
||||
<virtualport type="openvswitch">
|
||||
<parameters interfaceid='${nic.ovs_interfaceid}'/>
|
||||
</virtualport>
|
||||
</interface>
|
||||
#else
|
||||
<interface type='bridge'>
|
||||
<source bridge='${nic.bridge_name}'/>
|
||||
|
@@ -103,7 +103,9 @@ class LibvirtBridgeDriver(VIFDriver):
|
||||
|
||||
|
||||
class LibvirtOpenVswitchDriver(VIFDriver):
|
||||
"""VIF driver for Open vSwitch."""
|
||||
"""VIF driver for Open vSwitch that uses type='ethernet'
|
||||
libvirt XML. Used for libvirt versions that do not support
|
||||
OVS virtual port XML (0.9.10 or earlier)."""
|
||||
|
||||
def get_dev_name(_self, iface_id):
|
||||
return "tap" + iface_id[0:11]
|
||||
@@ -132,6 +134,8 @@ class LibvirtOpenVswitchDriver(VIFDriver):
|
||||
"external-ids:iface-status=active",
|
||||
'--', 'set', 'Interface', dev,
|
||||
"external-ids:attached-mac=%s" % mapping['mac'],
|
||||
'--', 'set', 'Interface', dev,
|
||||
"external-ids:vm-uuid=%s" % instance['uuid'],
|
||||
run_as_root=True)
|
||||
|
||||
result = {
|
||||
@@ -152,3 +156,19 @@ class LibvirtOpenVswitchDriver(VIFDriver):
|
||||
LOG.warning(_("Failed while unplugging vif of instance '%s'"),
|
||||
instance['name'])
|
||||
raise
|
||||
|
||||
|
||||
class LibvirtOpenVswitchVirtualPortDriver(VIFDriver):
|
||||
"""VIF driver for Open vSwitch that uses integrated libvirt
|
||||
OVS virtual port XML (introduced in libvirt 0.9.11)."""
|
||||
|
||||
def plug(self, instance, network, mapping):
|
||||
""" Pass data required to create OVS virtual port element"""
|
||||
return {
|
||||
'bridge_name': FLAGS.libvirt_ovs_bridge,
|
||||
'ovs_interfaceid': mapping['vif_uuid'],
|
||||
'mac_address': mapping['mac']}
|
||||
|
||||
def unplug(self, instance, network, mapping):
|
||||
"""No action needed. Libvirt takes care of cleanup"""
|
||||
pass
|
||||
|
Reference in New Issue
Block a user