From 87e6697906d577690404815a6cf98ef922952b90 Mon Sep 17 00:00:00 2001 From: Itzik Brown Date: Mon, 1 Jul 2013 17:13:44 +0300 Subject: [PATCH] Adding VIF Driver to support Mellanox Plugin blueprint mellanox-vif-driver DocImpact Change-Id: Ic98db496a3e175c9dee98657609a66934c41d557 --- etc/nova/rootwrap.d/network.filters | 3 + nova/network/model.py | 1 + nova/network/neutronv2/api.py | 6 ++ nova/tests/network/test_manager.py | 5 +- .../tests/virt/libvirt/test_libvirt_config.py | 16 ++++++ nova/tests/virt/libvirt/test_libvirt_vif.py | 26 +++++++++ nova/virt/libvirt/designer.py | 11 ++++ nova/virt/libvirt/vif.py | 55 +++++++++++++++++++ 8 files changed, 122 insertions(+), 1 deletion(-) diff --git a/etc/nova/rootwrap.d/network.filters b/etc/nova/rootwrap.d/network.filters index b3f0e544332d..0c99ceff5971 100644 --- a/etc/nova/rootwrap.d/network.filters +++ b/etc/nova/rootwrap.d/network.filters @@ -42,6 +42,9 @@ ivs-ctl: CommandFilter, ivs-ctl, root # nova/virt/libvirt/vif.py: 'ifc_ctl', ... ifc_ctl: CommandFilter, /opt/pg/bin/0/ifc_ctl, root +# nova/virt/libvirt/vif.py: 'ebrctl', ... +ebrctl: CommandFilter, ebrctl, root + # nova/network/linux_net.py: 'ebtables', '-D' ... # nova/network/linux_net.py: 'ebtables', '-I' ... ebtables: CommandFilter, ebtables, root diff --git a/nova/network/model.py b/nova/network/model.py index e189c8783370..eac88b579ed6 100644 --- a/nova/network/model.py +++ b/nova/network/model.py @@ -36,6 +36,7 @@ VIF_TYPE_IOVISOR = 'iovisor' VIF_TYPE_BRIDGE = 'bridge' VIF_TYPE_802_QBG = '802.1qbg' VIF_TYPE_802_QBH = '802.1qbh' +VIF_TYPE_MLNX_DIRECT = 'mlnx_direct' VIF_TYPE_OTHER = 'other' # Constant for max length of network interface names diff --git a/nova/network/neutronv2/api.py b/nova/network/neutronv2/api.py index bd887eb138bb..186cff90a38a 100644 --- a/nova/network/neutronv2/api.py +++ b/nova/network/neutronv2/api.py @@ -928,6 +928,12 @@ class API(base.Base): tenant_id=net['tenant_id'] ) network['subnets'] = subnets + port_profile = port.get('binding:profile') + if port_profile: + physical_network = port_profile.get('physical_network') + if physical_network: + network['physical_network'] = physical_network + if should_create_bridge is not None: network['should_create_bridge'] = should_create_bridge return network, ovs_interfaceid diff --git a/nova/tests/network/test_manager.py b/nova/tests/network/test_manager.py index c0d6a0a4f884..6bd3409b7f6b 100644 --- a/nova/tests/network/test_manager.py +++ b/nova/tests/network/test_manager.py @@ -191,6 +191,7 @@ class FlatNetworkTestCase(test.TestCase): 'ip_v6': '2001:db8:0:1::%x' % nid, 'netmask': '255.255.255.0', 'netmask_v6': 64, + 'physical_network': None, } network = vif['network'] @@ -229,7 +230,9 @@ class FlatNetworkTestCase(test.TestCase): ip=net_v4['ips'][i]['address'], ip_v6=net_v6['ips'][i]['address'], netmask=str(net_v4.as_netaddr().netmask), - netmask_v6=net_v6.as_netaddr()._prefixlen) + netmask_v6=net_v6.as_netaddr()._prefixlen, + physical_network= + network.get_meta('physical_network', None)) self.assertThat(vif_dict, matchers.DictMatches(check)) diff --git a/nova/tests/virt/libvirt/test_libvirt_config.py b/nova/tests/virt/libvirt/test_libvirt_config.py index db3b9c1b292e..3b5691cc7c96 100644 --- a/nova/tests/virt/libvirt/test_libvirt_config.py +++ b/nova/tests/virt/libvirt/test_libvirt_config.py @@ -767,6 +767,22 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest): """) + def test_config_direct(self): + obj = config.LibvirtConfigGuestInterface() + obj.net_type = "direct" + obj.mac_addr = "DE:AD:BE:EF:CA:FE" + obj.model = "virtio" + obj.source_dev = "eth0" + obj.source_mode = "passthrough" + + xml = obj.to_xml() + self.assertXmlEqual(xml, """ + + + + + """) + class LibvirtConfigGuestTest(LibvirtConfigBaseTest): diff --git a/nova/tests/virt/libvirt/test_libvirt_vif.py b/nova/tests/virt/libvirt/test_libvirt_vif.py index 13e49d0ab5f0..a1df6c736731 100644 --- a/nova/tests/virt/libvirt/test_libvirt_vif.py +++ b/nova/tests/virt/libvirt/test_libvirt_vif.py @@ -157,6 +157,19 @@ class LibvirtVifTestCase(test.TestCase): typeidversion="1", instanceid="ddd-eee-fff")) + network_mlnx = network_model.Network(id='network-id-xxx-yyy-zzz', + label=None, + bridge=None, + subnets=[subnet_bridge_4, + subnet_bridge_6], + interface='eth0') + + vif_mlnx = network_model.VIF(id='vif-xxx-yyy-zzz', + address='ca:fe:de:ad:be:ef', + network=network_mlnx, + type=network_model.VIF_TYPE_MLNX_DIRECT, + devname='tap-xxx-yyy-zzz') + instance = { 'name': 'instance-name', 'uuid': 'instance-uuid' @@ -488,6 +501,19 @@ class LibvirtVifTestCase(test.TestCase): self.vif_ivs, br_want) + def test_mlnx_direct_vif_driver(self): + d = vif.LibvirtGenericVIFDriver(self._get_conn()) + xml = self._get_instance_xml(d, + self.vif_mlnx) + node = self._get_node(xml) + self.assertEqual(node.get("type"), "direct") + self._assertTypeEquals(node, "direct", "source", + "dev", "eth-xxx-yyy-zzz") + self._assertTypeEquals(node, "direct", "source", + "mode", "passthrough") + self._assertMacEquals(node, self.vif_mlnx) + self._assertModel(xml, "virtio") + def test_generic_8021qbh_driver(self): d = vif.LibvirtGenericVIFDriver(self._get_conn()) xml = self._get_instance_xml(d, self.vif_8021qbh) diff --git a/nova/virt/libvirt/designer.py b/nova/virt/libvirt/designer.py index bcf976c79241..bb229fc67f19 100644 --- a/nova/virt/libvirt/designer.py +++ b/nova/virt/libvirt/designer.py @@ -106,6 +106,17 @@ def set_vif_host_backend_802qbh_config(conf, devname, profileid, conf.target_dev = tapname +def set_vif_host_backend_direct_config(conf, devname): + """Populate a LibvirtConfigGuestInterface instance + with direct Interface. + """ + + conf.net_type = "direct" + conf.source_mode = "passthrough" + conf.source_dev = devname + conf.model = "virtio" + + def set_vif_bandwidth_config(conf, inst_type): """Config vif inbound/outbound bandwidth limit. parameters are set in instance_type_extra_specs table, key is in the format diff --git a/nova/virt/libvirt/vif.py b/nova/virt/libvirt/vif.py index c3e2c9235e8f..047d1ac01713 100644 --- a/nova/virt/libvirt/vif.py +++ b/nova/virt/libvirt/vif.py @@ -54,6 +54,7 @@ CONF.import_opt('use_ipv6', 'nova.netconf') # Since libvirt 0.9.11, # supports OpenVSwitch natively. LIBVIRT_OVS_VPORT_VERSION = 9011 +DEV_PREFIX_ETH = 'eth' def is_vif_model_valid_for_virt(virt_type, vif_model): @@ -94,6 +95,10 @@ class LibvirtBaseVIFDriver(object): 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_config(self, instance, vif, image_meta, inst_type): conf = vconfig.LibvirtConfigGuestInterface() # Default to letting libvirt / the hypervisor choose the model @@ -296,6 +301,17 @@ class LibvirtGenericVIFDriver(LibvirtBaseVIFDriver): return conf + def get_config_mlnx_direct(self, instance, vif, image_meta, + inst_type): + conf = super(LibvirtGenericVIFDriver, + self).get_config(instance, vif, + image_meta, inst_type) + + devname = self.get_vif_devname_with_prefix(vif, DEV_PREFIX_ETH) + designer.set_vif_host_backend_direct_config(conf, devname) + + return conf + def get_config(self, instance, vif, image_meta, inst_type): vif_type = vif['type'] @@ -338,6 +354,11 @@ class LibvirtGenericVIFDriver(LibvirtBaseVIFDriver): vif, image_meta, inst_type) + elif vif_type == network_model.VIF_TYPE_MLNX_DIRECT: + return self.get_config_mlnx_direct(instance, + vif, + image_meta, + inst_type) else: raise exception.NovaException( _("Unexpected vif_type=%s") % vif_type) @@ -465,6 +486,23 @@ class LibvirtGenericVIFDriver(LibvirtBaseVIFDriver): else: self.plug_ivs_ethernet(instance, vif) + def plug_mlnx_direct(self, instance, vif): + super(LibvirtGenericVIFDriver, + self).plug(instance, vif) + + network = vif['network'] + vnic_mac = vif['address'] + device_id = instance['uuid'] + fabric = network['meta']['physical_network'] + + dev_name = self.get_vif_devname_with_prefix(vif, DEV_PREFIX_ETH) + try: + utils.execute('ebrctl', 'add-port', vnic_mac, device_id, fabric, + network_model.VIF_TYPE_MLNX_DIRECT, dev_name, + run_as_root=True) + except processutils.ProcessExecutionError: + LOG.exception(_("Failed while plugging vif"), instance=instance) + def plug_802qbg(self, instance, vif): super(LibvirtGenericVIFDriver, self).plug(instance, vif) @@ -521,6 +559,8 @@ class LibvirtGenericVIFDriver(LibvirtBaseVIFDriver): self.plug_ivs(instance, vif) elif vif_type == network_model.VIF_TYPE_IOVISOR: self.plug_iovisor(instance, vif) + elif vif_type == network_model.VIF_TYPE_MLNX_DIRECT: + self.plug_mlnx_direct(instance, vif) else: raise exception.NovaException( _("Unexpected vif_type=%s") % vif_type) @@ -614,6 +654,19 @@ class LibvirtGenericVIFDriver(LibvirtBaseVIFDriver): else: self.unplug_ivs_ethernet(instance, vif) + def unplug_mlnx_direct(self, instance, vif): + super(LibvirtGenericVIFDriver, + self).unplug(instance, vif) + + network = vif['network'] + vnic_mac = vif['address'] + fabric = network['meta']['physical_network'] + try: + utils.execute('ebrctl', 'del-port', fabric, + vnic_mac, run_as_root=True) + except processutils.ProcessExecutionError: + LOG.exception(_("Failed while unplugging vif"), instance=instance) + def unplug_802qbg(self, instance, vif): super(LibvirtGenericVIFDriver, self).unplug(instance, vif) @@ -667,6 +720,8 @@ class LibvirtGenericVIFDriver(LibvirtBaseVIFDriver): self.unplug_ivs(instance, vif) elif vif_type == network_model.VIF_TYPE_IOVISOR: self.unplug_iovisor(instance, vif) + elif vif_type == network_model.VIF_TYPE_MLNX_DIRECT: + self.unplug_mlnx_direct(instance, vif) else: raise exception.NovaException( _("Unexpected vif_type=%s") % vif_type)