diff --git a/nova/tests/test_libvirt_vif.py b/nova/tests/test_libvirt_vif.py index 3861d7dfa8ee..7ce81cc09925 100644 --- a/nova/tests/test_libvirt_vif.py +++ b/nova/tests/test_libvirt_vif.py @@ -16,6 +16,8 @@ from lxml import etree +from nova import exception +from nova.network import model as network_model from nova.openstack.common import cfg from nova import test from nova import utils @@ -48,7 +50,8 @@ class LibvirtVifTestCase(test.TestCase): 'ips': [{'ip': '101.168.1.9'}], 'dhcp_server': '191.168.1.1', 'vif_uuid': 'vif-xxx-yyy-zzz', - 'vif_devname': 'tap-xxx-yyy-zzz' + 'vif_devname': 'tap-xxx-yyy-zzz', + 'vif_type': network_model.VIF_TYPE_BRIDGE, } net_ovs = { @@ -75,6 +78,15 @@ class LibvirtVifTestCase(test.TestCase): 'ovs_interfaceid': 'aaa-bbb-ccc', } + mapping_none = { + 'mac': 'ca:fe:de:ad:be:ef', + 'gateway_v6': net_bridge['gateway_v6'], + 'ips': [{'ip': '101.168.1.9'}], + 'dhcp_server': '191.168.1.1', + 'vif_uuid': 'vif-xxx-yyy-zzz', + 'vif_devname': 'tap-xxx-yyy-zzz', + } + instance = { 'name': 'instance-name', 'uuid': 'instance-uuid' @@ -149,7 +161,7 @@ class LibvirtVifTestCase(test.TestCase): self.flags(libvirt_use_virtio_for_bridges=False, libvirt_type='kvm') - d = vif.LibvirtBridgeDriver() + d = vif.LibvirtGenericVIFDriver() xml = self._get_instance_xml(d, self.net_bridge, self.mapping_bridge) @@ -168,7 +180,7 @@ class LibvirtVifTestCase(test.TestCase): self.flags(libvirt_use_virtio_for_bridges=True, libvirt_type='kvm') - d = vif.LibvirtBridgeDriver() + d = vif.LibvirtGenericVIFDriver() xml = self._get_instance_xml(d, self.net_bridge, self.mapping_bridge) @@ -187,7 +199,7 @@ class LibvirtVifTestCase(test.TestCase): self.flags(libvirt_use_virtio_for_bridges=True, libvirt_type='qemu') - d = vif.LibvirtBridgeDriver() + d = vif.LibvirtGenericVIFDriver() xml = self._get_instance_xml(d, self.net_bridge, self.mapping_bridge) @@ -206,7 +218,7 @@ class LibvirtVifTestCase(test.TestCase): self.flags(libvirt_use_virtio_for_bridges=True, libvirt_type='xen') - d = vif.LibvirtBridgeDriver() + d = vif.LibvirtGenericVIFDriver() xml = self._get_instance_xml(d, self.net_bridge, self.mapping_bridge) @@ -221,8 +233,15 @@ class LibvirtVifTestCase(test.TestCase): ret = node.findall("driver") self.assertEqual(len(ret), 0) - def test_bridge_driver(self): - d = vif.LibvirtBridgeDriver() + def test_generic_driver_none(self): + d = vif.LibvirtGenericVIFDriver() + self.assertRaises(exception.NovaException, + self._get_instance_xml, + d, + self.net_bridge, + self.mapping_none) + + def _check_bridge_driver(self, d): xml = self._get_instance_xml(d, self.net_bridge, self.mapping_bridge) @@ -237,6 +256,14 @@ class LibvirtVifTestCase(test.TestCase): mac = node.find("mac").get("address") self.assertEqual(mac, self.mapping_bridge['mac']) + def test_bridge_driver(self): + d = vif.LibvirtBridgeDriver() + self._check_bridge_driver(d) + + def test_generic_driver_bridge(self): + d = vif.LibvirtGenericVIFDriver() + self._check_bridge_driver(d) + def test_ovs_ethernet_driver(self): d = vif.LibvirtOpenVswitchDriver() xml = self._get_instance_xml(d, diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 7439ad40ad6c..9e6d7350d85e 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -140,7 +140,7 @@ libvirt_opts = [ 'raw, qcow2, vmdk, vdi). ' 'Defaults to same as source image'), cfg.StrOpt('libvirt_vif_driver', - default='nova.virt.libvirt.vif.LibvirtBridgeDriver', + default='nova.virt.libvirt.vif.LibvirtGenericVIFDriver', help='The libvirt VIF driver to configure the VIFs.'), cfg.ListOpt('libvirt_volume_drivers', default=[ diff --git a/nova/virt/libvirt/vif.py b/nova/virt/libvirt/vif.py index d90a5e2952e5..f185e8efd320 100644 --- a/nova/virt/libvirt/vif.py +++ b/nova/virt/libvirt/vif.py @@ -72,19 +72,22 @@ class LibvirtBaseVIFDriver(object): return conf + def plug(self, instance, vif): + pass -class LibvirtBridgeDriver(LibvirtBaseVIFDriver): - """VIF driver for Linux bridge.""" + def unplug(self, instance, vif): + pass + + +class LibvirtGenericVIFDriver(LibvirtBaseVIFDriver): + """Generic VIF driver for libvirt networking.""" def get_bridge_name(self, network): return network['bridge'] - def get_config(self, instance, network, mapping): + def get_config_bridge(self, instance, network, mapping): """Get VIF configurations for bridge type.""" - - mac_id = mapping['mac'].replace(':', '') - - conf = super(LibvirtBridgeDriver, + conf = super(LibvirtGenericVIFDriver, self).get_config(instance, network, mapping) @@ -93,6 +96,7 @@ class LibvirtBridgeDriver(LibvirtBaseVIFDriver): conf, self.get_bridge_name(network), self.get_vif_devname(mapping)) + mac_id = mapping['mac'].replace(':', '') name = "nova-instance-" + instance['name'] + "-" + mac_id primary_addr = mapping['ips'][0]['ip'] dhcp_server = ra_server = ipv4_cidr = ipv6_cidr = None @@ -112,8 +116,29 @@ class LibvirtBridgeDriver(LibvirtBaseVIFDriver): return conf - def plug(self, instance, vif): + def get_config(self, instance, network, mapping): + vif_type = mapping.get('vif_type') + + LOG.debug(_("vif_type=%(vif_type)s instance=%(instance)s " + "network=%(network)s mapping=%(mapping)s") + % locals()) + + if vif_type is None: + raise exception.NovaException( + _("vif_type parameter must be present " + "for this vif_driver implementation")) + + if vif_type == network_model.VIF_TYPE_BRIDGE: + return self.get_config_bridge(instance, network, mapping) + else: + raise exception.NovaException( + _("Unexpected vif_type=%s") % vif_type) + + def plug_bridge(self, instance, vif): """Ensure that the bridge exists, and add VIF to it.""" + super(LibvirtGenericVIFDriver, + self).plug(instance, vif) + network, mapping = vif if (not network.get('multi_host') and mapping.get('should_create_bridge')): @@ -135,9 +160,71 @@ class LibvirtBridgeDriver(LibvirtBaseVIFDriver): self.get_bridge_name(network), iface) - def unplug(self, instance, vif): + def plug(self, instance, vif): + network, mapping = vif + vif_type = mapping.get('vif_type') + + LOG.debug(_("vif_type=%(vif_type)s instance=%(instance)s " + "network=%(network)s mapping=%(mapping)s") + % locals()) + + if vif_type is None: + raise exception.NovaException( + _("vif_type parameter must be present " + "for this vif_driver implementation")) + + if vif_type == network_model.VIF_TYPE_BRIDGE: + self.plug_bridge(instance, vif) + else: + raise exception.NovaException( + _("Unexpected vif_type=%s") % vif_type) + + def unplug_bridge(self, instance, vif): """No manual unplugging required.""" - pass + super(LibvirtGenericVIFDriver, + self).unplug(instance, vif) + + def unplug(self, instance, vif): + network, mapping = vif + vif_type = mapping.get('vif_type') + + LOG.debug(_("vif_type=%(vif_type)s instance=%(instance)s " + "network=%(network)s mapping=%(mapping)s") + % locals()) + + if vif_type is None: + raise exception.NovaException( + _("vif_type parameter must be present " + "for this vif_driver implementation")) + + if vif_type == network_model.VIF_TYPE_BRIDGE: + self.unplug_bridge(instance, vif) + else: + raise exception.NovaException( + _("Unexpected vif_type=%s") % vif_type) + + +class LibvirtBridgeDriver(LibvirtGenericVIFDriver): + """Deprecated in favour of LibvirtGenericVIFDriver. + Retained in Grizzly for compatibility with Quantum + drivers which do not yet report 'vif_type' port binding. + To be removed in Hxxxx.""" + + def __init__(self): + LOG.deprecated( + _("LibvirtBridgeDriver is deprecated and " + "will be removed in the Hxxxx release. Please " + "update the 'libvirt_vif_driver' config parameter " + "to use the LibvirtGenericVIFDriver class instead")) + + def get_config(self, instance, network, mapping): + return self.get_config_bridge(instance, network, mapping) + + def plug(self, instance, vif): + self.plug_bridge(instance, vif) + + def unplug(self, instance, vif): + self.unplug_bridge(instance, vif) class LibvirtOpenVswitchDriver(LibvirtBaseVIFDriver):