summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorKevin Benton <kevin.benton@bigswitch.com>2013-06-04 17:47:59 -0700
committerKevin Benton <kevin.benton@bigswitch.com>2013-06-09 10:40:01 -0700
commit6caadd1c1badee8da046a42c796490d010e4e83f (patch)
tree7fcd08757aed3a4d91763f4c8a578c1e2635dbd8 /nova
parent2effda29c8926b87a240801acc4d61c62df0954b (diff)
downloadnova-6caadd1c1badee8da046a42c796490d010e4e83f.tar.gz
nova-6caadd1c1badee8da046a42c796490d010e4e83f.tar.xz
nova-6caadd1c1badee8da046a42c796490d010e4e83f.zip
Adds support for the Indigo Virtual Switch (IVS)
Implements: blueprint ivs-vif-driver Adds line to rootwrap config to allow call to ivs-ctl to control the Indigo switch. Adds a new 'ivs' VIF type in network/model.py. Adds support to the LibvirtGenericVIFDriver class for the IVS switch. Adds functions to linux_net.py to create and delete IVS vif ports. Adds unit tests to test the new IVS methods. Change-Id: I65436b82f65374103644af8aba9dba14ba73f94c
Diffstat (limited to 'nova')
-rw-r--r--nova/network/linux_net.py12
-rw-r--r--nova/network/model.py1
-rw-r--r--nova/tests/virt/libvirt/test_libvirt_vif.py80
-rw-r--r--nova/virt/libvirt/vif.py131
4 files changed, 218 insertions, 6 deletions
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index dad496f23..2078d5c18 100644
--- a/nova/network/linux_net.py
+++ b/nova/network/linux_net.py
@@ -1259,6 +1259,18 @@ def delete_ovs_vif_port(bridge, dev):
delete_net_dev(dev)
+def create_ivs_vif_port(dev, iface_id, mac, instance_id):
+ utils.execute('ivs-ctl', 'add-port',
+ dev, run_as_root=True)
+
+
+def delete_ivs_vif_port(dev):
+ utils.execute('ivs-ctl', 'del-port', dev,
+ run_as_root=True)
+ utils.execute('ip', 'link', 'delete', dev,
+ run_as_root=True)
+
+
def create_tap_dev(dev, mac_address=None):
if not device_exists(dev):
try:
diff --git a/nova/network/model.py b/nova/network/model.py
index 240911ea9..80b6eb051 100644
--- a/nova/network/model.py
+++ b/nova/network/model.py
@@ -30,6 +30,7 @@ def ensure_string_keys(d):
# Constants for the 'vif_type' field in VIF class
VIF_TYPE_OVS = 'ovs'
+VIF_TYPE_IVS = 'ivs'
VIF_TYPE_BRIDGE = 'bridge'
VIF_TYPE_802_QBG = '802.1qbg'
VIF_TYPE_802_QBH = '802.1qbh'
diff --git a/nova/tests/virt/libvirt/test_libvirt_vif.py b/nova/tests/virt/libvirt/test_libvirt_vif.py
index c9c6aef12..7cbf67b07 100644
--- a/nova/tests/virt/libvirt/test_libvirt_vif.py
+++ b/nova/tests/virt/libvirt/test_libvirt_vif.py
@@ -103,6 +103,17 @@ class LibvirtVifTestCase(test.TestCase):
'ovs_interfaceid': 'aaa-bbb-ccc',
}
+ mapping_ivs = {
+ 'mac': 'ca:fe:de:ad:be:ef',
+ 'gateway_v6': net_ovs['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',
+ 'vif_type': network_model.VIF_TYPE_IVS,
+ 'ivs_interfaceid': 'aaa-bbb-ccc',
+ }
+
mapping_ovs_legacy = {
'mac': 'ca:fe:de:ad:be:ef',
'gateway_v6': net_ovs['gateway_v6'],
@@ -411,6 +422,24 @@ class LibvirtVifTestCase(test.TestCase):
self.mapping_bridge_quantum,
br_want)
+ def _check_ivs_ethernet_driver(self, d, net, mapping, dev_prefix):
+ self.flags(firewall_driver="nova.virt.firewall.NoopFirewallDriver")
+ xml = self._get_instance_xml(d, net, mapping)
+
+ doc = etree.fromstring(xml)
+ ret = doc.findall('./devices/interface')
+ self.assertEqual(len(ret), 1)
+ node = ret[0]
+ ret = node.findall("filterref")
+ self.assertEqual(len(ret), 0)
+ self.assertEqual(node.get("type"), "ethernet")
+ dev_name = node.find("target").get("dev")
+ self.assertTrue(dev_name.startswith(dev_prefix))
+ mac = node.find("mac").get("address")
+ self.assertEqual(mac, self.mapping_ivs['mac'])
+ script = node.find("script").get("path")
+ self.assertEquals(script, "")
+
def _check_ovs_ethernet_driver(self, d, net, mapping, dev_prefix):
self.flags(firewall_driver="nova.virt.firewall.NoopFirewallDriver")
xml = self._get_instance_xml(d, net, mapping)
@@ -451,6 +480,33 @@ class LibvirtVifTestCase(test.TestCase):
self.mapping_ovs,
"tap")
+ def test_ivs_ethernet_driver(self):
+ def get_connection():
+ return fakelibvirt.Connection("qemu:///session",
+ False,
+ 9010)
+ d = vif.LibvirtGenericVIFDriver(get_connection)
+ self._check_ivs_ethernet_driver(d,
+ self.net_ovs,
+ self.mapping_ivs,
+ "tap")
+
+ def _check_ivs_virtualport_driver(self, d, net, mapping, want_iface_id):
+ self.flags(firewall_driver="nova.virt.firewall.NoopFirewallDriver")
+ xml = self._get_instance_xml(d, net, mapping)
+ doc = etree.fromstring(xml)
+ ret = doc.findall('./devices/interface')
+ self.assertEqual(len(ret), 1)
+ node = ret[0]
+ ret = node.findall("filterref")
+ self.assertEqual(len(ret), 0)
+ self.assertEqual(node.get("type"), "ethernet")
+
+ tap_name = node.find("target").get("dev")
+ self.assertEqual(tap_name, mapping['vif_devname'])
+ mac = node.find("mac").get("address")
+ self.assertEqual(mac, mapping['mac'])
+
def _check_ovs_virtualport_driver(self, d, net, mapping, want_iface_id):
self.flags(firewall_driver="nova.virt.firewall.NoopFirewallDriver")
xml = self._get_instance_xml(d, net, mapping)
@@ -502,6 +558,18 @@ class LibvirtVifTestCase(test.TestCase):
self.mapping_ovs,
want_iface_id)
+ def test_generic_ivs_virtualport_driver(self):
+ def get_connection():
+ return fakelibvirt.Connection("qemu:///session",
+ False,
+ 9011)
+ d = vif.LibvirtGenericVIFDriver(get_connection)
+ want_iface_id = self.mapping_ivs['ivs_interfaceid']
+ self._check_ivs_virtualport_driver(d,
+ self.net_ovs,
+ self.mapping_ivs,
+ want_iface_id)
+
def _check_quantum_hybrid_driver(self, d, net, mapping, br_want):
self.flags(firewall_driver="nova.virt.firewall.IptablesFirewallDriver")
xml = self._get_instance_xml(d, net, mapping)
@@ -542,6 +610,18 @@ class LibvirtVifTestCase(test.TestCase):
self.mapping_ovs,
br_want)
+ def test_ivs_hybrid_driver(self):
+ def get_connection():
+ return fakelibvirt.Connection("qemu:///session",
+ False)
+ d = vif.LibvirtGenericVIFDriver(get_connection)
+ br_want = "qbr" + self.mapping_ivs['vif_uuid']
+ br_want = br_want[:network_model.NIC_NAME_LEN]
+ self._check_quantum_hybrid_driver(d,
+ self.net_ovs,
+ self.mapping_ivs,
+ br_want)
+
def test_generic_8021qbh_driver(self):
def get_connection():
return fakelibvirt.Connection("qemu:///session",
diff --git a/nova/virt/libvirt/vif.py b/nova/virt/libvirt/vif.py
index 28c481cfe..3fb9641b7 100644
--- a/nova/virt/libvirt/vif.py
+++ b/nova/virt/libvirt/vif.py
@@ -228,6 +228,36 @@ class LibvirtGenericVIFDriver(LibvirtBaseVIFDriver):
mapping,
image_meta)
+ def get_config_ivs_hybrid(self, instance, network, mapping, image_meta):
+ newnet = copy.deepcopy(network)
+ newnet['bridge'] = self.get_br_name(mapping['vif_uuid'])
+ return self.get_config_bridge(instance,
+ newnet,
+ mapping,
+ image_meta)
+
+ def get_config_ivs_ethernet(self, instance, network, mapping, image_meta):
+ conf = super(LibvirtGenericVIFDriver,
+ self).get_config(instance,
+ network,
+ mapping,
+ image_meta)
+
+ dev = self.get_vif_devname(mapping)
+ designer.set_vif_host_backend_ethernet_config(conf, dev)
+
+ return conf
+
+ def get_config_ivs(self, instance, network, mapping, image_meta):
+ if self.get_firewall_required():
+ return self.get_config_ivs_hybrid(instance, network,
+ mapping,
+ image_meta)
+ else:
+ return self.get_config_ivs_ethernet(instance, network,
+ mapping,
+ image_meta)
+
def get_config_802qbg(self, instance, network, mapping, image_meta):
conf = super(LibvirtGenericVIFDriver,
self).get_config(instance,
@@ -270,8 +300,7 @@ class LibvirtGenericVIFDriver(LibvirtBaseVIFDriver):
raise exception.NovaException(
_("vif_type parameter must be present "
"for this vif_driver implementation"))
-
- if vif_type == network_model.VIF_TYPE_BRIDGE:
+ elif vif_type == network_model.VIF_TYPE_BRIDGE:
return self.get_config_bridge(instance,
network, mapping,
image_meta)
@@ -287,6 +316,10 @@ class LibvirtGenericVIFDriver(LibvirtBaseVIFDriver):
return self.get_config_802qbh(instance,
network, mapping,
image_meta)
+ elif vif_type == network_model.VIF_TYPE_IVS:
+ return self.get_config_ivs(instance,
+ network, mapping,
+ image_meta)
else:
raise exception.NovaException(
_("Unexpected vif_type=%s") % vif_type)
@@ -371,6 +404,51 @@ class LibvirtGenericVIFDriver(LibvirtBaseVIFDriver):
else:
self.plug_ovs_ethernet(instance, vif)
+ def plug_ivs_ethernet(self, instance, vif):
+ super(LibvirtGenericVIFDriver,
+ self).plug(instance, vif)
+
+ network, mapping = vif
+ iface_id = self.get_ovs_interfaceid(mapping)
+ dev = self.get_vif_devname(mapping)
+ linux_net.create_tap_dev(dev)
+ linux_net.create_ivs_vif_port(dev, iface_id, mapping['mac'],
+ instance['uuid'])
+
+ def plug_ivs_hybrid(self, instance, vif):
+ """Plug using hybrid strategy (same as OVS)
+
+ Create a per-VIF linux bridge, then link that bridge to the OVS
+ integration bridge via a veth device, setting up the other end
+ of the veth device just like a normal IVS port. Then boot the
+ VIF on the linux bridge using standard libvirt mechanisms.
+ """
+ super(LibvirtGenericVIFDriver,
+ self).plug(instance, vif)
+
+ network, mapping = vif
+ iface_id = self.get_ovs_interfaceid(mapping)
+ br_name = self.get_br_name(mapping['vif_uuid'])
+ v1_name, v2_name = self.get_veth_pair_names(mapping['vif_uuid'])
+
+ 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)
+
+ 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_ivs_vif_port(v2_name, iface_id, mapping['mac'],
+ instance['uuid'])
+
+ def plug_ivs(self, instance, vif):
+ if self.get_firewall_required():
+ self.plug_ivs_hybrid(instance, vif)
+ else:
+ self.plug_ivs_ethernet(instance, vif)
+
def plug_802qbg(self, instance, vif):
super(LibvirtGenericVIFDriver,
self).plug(instance, vif)
@@ -391,8 +469,7 @@ class LibvirtGenericVIFDriver(LibvirtBaseVIFDriver):
raise exception.NovaException(
_("vif_type parameter must be present "
"for this vif_driver implementation"))
-
- if vif_type == network_model.VIF_TYPE_BRIDGE:
+ elif vif_type == network_model.VIF_TYPE_BRIDGE:
self.plug_bridge(instance, vif)
elif vif_type == network_model.VIF_TYPE_OVS:
self.plug_ovs(instance, vif)
@@ -400,6 +477,8 @@ class LibvirtGenericVIFDriver(LibvirtBaseVIFDriver):
self.plug_802qbg(instance, vif)
elif vif_type == network_model.VIF_TYPE_802_QBH:
self.plug_802qbh(instance, vif)
+ elif vif_type == network_model.VIF_TYPE_IVS:
+ self.plug_ivs(instance, vif)
else:
raise exception.NovaException(
_("Unexpected vif_type=%s") % vif_type)
@@ -458,6 +537,45 @@ class LibvirtGenericVIFDriver(LibvirtBaseVIFDriver):
else:
self.unplug_ovs_ethernet(instance, vif)
+ def unplug_ivs_ethernet(self, instance, vif):
+ """Unplug the VIF by deleting the port from the bridge."""
+ super(LibvirtGenericVIFDriver,
+ self).unplug(instance, vif)
+
+ try:
+ network, mapping = vif
+ linux_net.delete_ivs_vif_port(self.get_vif_devname(mapping))
+ except exception.ProcessExecutionError:
+ LOG.exception(_("Failed while unplugging vif"), instance=instance)
+
+ def unplug_ivs_hybrid(self, instance, vif):
+ """UnPlug using hybrid strategy (same as OVS)
+
+ Unhook port from IVS, unhook port from bridge, delete
+ bridge, and delete both veth devices.
+ """
+ super(LibvirtGenericVIFDriver,
+ self).unplug(instance, vif)
+
+ try:
+ network, mapping = vif
+ br_name = self.get_br_name(mapping['vif_uuid'])
+ v1_name, v2_name = self.get_veth_pair_names(mapping['vif_uuid'])
+
+ 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_ivs_vif_port(v2_name)
+ except exception.ProcessExecutionError:
+ LOG.exception(_("Failed while unplugging vif"), instance=instance)
+
+ def unplug_ivs(self, instance, vif):
+ if self.get_firewall_required():
+ self.unplug_ovs_hybrid(instance, vif)
+ else:
+ self.unplug_ovs_ethernet(instance, vif)
+
def unplug_802qbg(self, instance, vif):
super(LibvirtGenericVIFDriver,
self).unplug(instance, vif)
@@ -478,8 +596,7 @@ class LibvirtGenericVIFDriver(LibvirtBaseVIFDriver):
raise exception.NovaException(
_("vif_type parameter must be present "
"for this vif_driver implementation"))
-
- if vif_type == network_model.VIF_TYPE_BRIDGE:
+ elif vif_type == network_model.VIF_TYPE_BRIDGE:
self.unplug_bridge(instance, vif)
elif vif_type == network_model.VIF_TYPE_OVS:
self.unplug_ovs(instance, vif)
@@ -487,6 +604,8 @@ class LibvirtGenericVIFDriver(LibvirtBaseVIFDriver):
self.unplug_802qbg(instance, vif)
elif vif_type == network_model.VIF_TYPE_802_QBH:
self.unplug_802qbh(instance, vif)
+ elif vif_type == network_model.VIF_TYPE_IVS:
+ self.unplug_ivs(instance, vif)
else:
raise exception.NovaException(
_("Unexpected vif_type=%s") % vif_type)