Skip to content

Commit 29f83e6

Browse files
CLOUDSTACK-8239 - Adding support for virtio-scsi on KVM hosts
This adds support for virtio-scsi on KVM hosts, but currently only for guests that are associated with a new os_type of 'Other PV Virtio-SCSI (64-bit)'. This is to prevent device name changes on existing templates / VMs.
1 parent 61ce75e commit 29f83e6

File tree

6 files changed

+712
-225
lines changed

6 files changed

+712
-225
lines changed

plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@
125125
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InputDef;
126126
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
127127
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef.GuestNetType;
128+
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.SCSIDef;
128129
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.SerialDef;
129130
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.TermPolicy;
130131
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.VideoDef;
@@ -2059,6 +2060,12 @@ So if getMinSpeed() returns null we fall back to getSpeed().
20592060
final InputDef input = new InputDef("tablet", "usb");
20602061
devices.addDevice(input);
20612062

2063+
// If we're using virtio scsi, then we need to add a virtual scsi controller
2064+
if (getGuestDiskModel(vmTO.getPlatformEmulator()) == DiskDef.DiskBus.SCSI) {
2065+
final SCSIDef sd = new SCSIDef((short)0, 0, 0, 9, 0);
2066+
devices.addDevice(sd);
2067+
}
2068+
20622069
vm.addComp(devices);
20632070

20642071
return vm;
@@ -2159,6 +2166,11 @@ public int compare(final DiskTO arg0, final DiskTO arg1) {
21592166
if (diskBusType == null) {
21602167
diskBusType = getGuestDiskModel(vmSpec.getPlatformEmulator());
21612168
}
2169+
2170+
// I'm not sure why previously certain DATADISKs were hard-coded VIRTIO and others not, however this
2171+
// maintains existing functionality with the exception that SCSI will override VIRTIO.
2172+
DiskDef.DiskBus diskBusTypeData = (diskBusType == DiskDef.DiskBus.SCSI) ? diskBusType : DiskDef.DiskBus.VIRTIO;
2173+
21622174
final DiskDef disk = new DiskDef();
21632175
if (volume.getType() == Volume.Type.ISO) {
21642176
if (volPath == null) {
@@ -2188,7 +2200,7 @@ public int compare(final DiskTO arg0, final DiskTO arg1) {
21882200
disk.defBlockBasedDisk(physicalDisk.getPath(), devId, diskBusType);
21892201
} else {
21902202
if (volume.getType() == Volume.Type.DATADISK) {
2191-
disk.defFileBasedDisk(physicalDisk.getPath(), devId, DiskDef.DiskBus.VIRTIO, DiskDef.DiskFmtType.QCOW2);
2203+
disk.defFileBasedDisk(physicalDisk.getPath(), devId, diskBusTypeData, DiskDef.DiskFmtType.QCOW2);
21922204
} else {
21932205
disk.defFileBasedDisk(physicalDisk.getPath(), devId, diskBusType, DiskDef.DiskFmtType.QCOW2);
21942206
}
@@ -2216,6 +2228,7 @@ public int compare(final DiskTO arg0, final DiskTO arg1) {
22162228
disk.setCacheMode(DiskDef.DiskCacheMode.valueOf(volumeObjectTO.getCacheMode().toString().toUpperCase()));
22172229
}
22182230
}
2231+
22192232
vm.getDevices().addDevice(disk);
22202233
}
22212234

@@ -2334,13 +2347,13 @@ public synchronized String attachOrDetachDisk(final Connect conn,
23342347
DiskDef diskdef = null;
23352348
final KVMStoragePool attachingPool = attachingDisk.getPool();
23362349
try {
2337-
if (!attach) {
2338-
dm = conn.domainLookupByName(vmName);
2339-
final LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
2340-
final String xml = dm.getXMLDesc(0);
2341-
parser.parseDomainXML(xml);
2342-
disks = parser.getDisks();
2350+
dm = conn.domainLookupByName(vmName);
2351+
final LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
2352+
final String domXml = dm.getXMLDesc(0);
2353+
parser.parseDomainXML(domXml);
2354+
disks = parser.getDisks();
23432355

2356+
if (!attach) {
23442357
for (final DiskDef disk : disks) {
23452358
final String file = disk.getDiskPath();
23462359
if (file != null && file.equalsIgnoreCase(attachingDisk.getPath())) {
@@ -2352,17 +2365,29 @@ public synchronized String attachOrDetachDisk(final Connect conn,
23522365
throw new InternalErrorException("disk: " + attachingDisk.getPath() + " is not attached before");
23532366
}
23542367
} else {
2368+
DiskDef.DiskBus busT = DiskDef.DiskBus.VIRTIO;
2369+
for (final DiskDef disk : disks) {
2370+
s_logger.debug("disk is type : "+disk.toString());
2371+
if (disk.getDeviceType() == DeviceType.DISK) {
2372+
if (disk.getBusType() == DiskDef.DiskBus.SCSI) {
2373+
busT = DiskDef.DiskBus.SCSI;
2374+
}
2375+
s_logger.debug("Disk bus type: " + disk.getDeviceType().toString() + ", busT: "+busT.toString());
2376+
break;
2377+
}
2378+
}
2379+
23552380
diskdef = new DiskDef();
23562381
if (attachingPool.getType() == StoragePoolType.RBD) {
23572382
diskdef.defNetworkBasedDisk(attachingDisk.getPath(), attachingPool.getSourceHost(), attachingPool.getSourcePort(), attachingPool.getAuthUserName(),
2358-
attachingPool.getUuid(), devId, DiskDef.DiskBus.VIRTIO, DiskProtocol.RBD, DiskDef.DiskFmtType.RAW);
2383+
attachingPool.getUuid(), devId, busT, DiskProtocol.RBD, DiskDef.DiskFmtType.RAW);
23592384
} else if (attachingPool.getType() == StoragePoolType.Gluster) {
23602385
diskdef.defNetworkBasedDisk(attachingDisk.getPath(), attachingPool.getSourceHost(), attachingPool.getSourcePort(), null,
2361-
null, devId, DiskDef.DiskBus.VIRTIO, DiskProtocol.GLUSTER, DiskDef.DiskFmtType.QCOW2);
2386+
null, devId, busT, DiskProtocol.GLUSTER, DiskDef.DiskFmtType.QCOW2);
23622387
} else if (attachingDisk.getFormat() == PhysicalDiskFormat.QCOW2) {
2363-
diskdef.defFileBasedDisk(attachingDisk.getPath(), devId, DiskDef.DiskBus.VIRTIO, DiskDef.DiskFmtType.QCOW2);
2388+
diskdef.defFileBasedDisk(attachingDisk.getPath(), devId, busT, DiskDef.DiskFmtType.QCOW2);
23642389
} else if (attachingDisk.getFormat() == PhysicalDiskFormat.RAW) {
2365-
diskdef.defBlockBasedDisk(attachingDisk.getPath(), devId, DiskDef.DiskBus.VIRTIO);
2390+
diskdef.defBlockBasedDisk(attachingDisk.getPath(), devId, busT);
23662391
}
23672392
if (bytesReadRate != null && bytesReadRate > 0) {
23682393
diskdef.setBytesReadRate(bytesReadRate);
@@ -2961,19 +2986,8 @@ private String getHypervisorPath(final Connect conn) {
29612986
}
29622987

29632988
boolean isGuestPVEnabled(final String guestOSName) {
2964-
if (guestOSName == null) {
2965-
return false;
2966-
}
2967-
if (guestOSName.startsWith("Ubuntu") || guestOSName.startsWith("Fedora 13") || guestOSName.startsWith("Fedora 12") || guestOSName.startsWith("Fedora 11") ||
2968-
guestOSName.startsWith("Fedora 10") || guestOSName.startsWith("Fedora 9") || guestOSName.startsWith("CentOS 5.3") || guestOSName.startsWith("CentOS 5.4") ||
2969-
guestOSName.startsWith("CentOS 5.5") || guestOSName.startsWith("CentOS") || guestOSName.startsWith("Fedora") ||
2970-
guestOSName.startsWith("Red Hat Enterprise Linux 5.3") || guestOSName.startsWith("Red Hat Enterprise Linux 5.4") ||
2971-
guestOSName.startsWith("Red Hat Enterprise Linux 5.5") || guestOSName.startsWith("Red Hat Enterprise Linux 6") || guestOSName.startsWith("Debian GNU/Linux") ||
2972-
guestOSName.startsWith("FreeBSD 10") || guestOSName.startsWith("Oracle") || guestOSName.startsWith("Other PV")) {
2973-
return true;
2974-
} else {
2975-
return false;
2976-
}
2989+
DiskDef.DiskBus db = getGuestDiskModel(guestOSName);
2990+
return db != DiskDef.DiskBus.IDE;
29772991
}
29782992

29792993
public boolean isCentosHost() {
@@ -2985,13 +2999,22 @@ public boolean isCentosHost() {
29852999
}
29863000

29873001
private DiskDef.DiskBus getGuestDiskModel(final String platformEmulator) {
2988-
if (isGuestPVEnabled(platformEmulator)) {
3002+
if (platformEmulator == null) {
3003+
return DiskDef.DiskBus.IDE;
3004+
} else if (platformEmulator.startsWith("Other PV Virtio-SCSI")) {
3005+
return DiskDef.DiskBus.SCSI;
3006+
} else if (platformEmulator.startsWith("Ubuntu") || platformEmulator.startsWith("Fedora 13") || platformEmulator.startsWith("Fedora 12") || platformEmulator.startsWith("Fedora 11") ||
3007+
platformEmulator.startsWith("Fedora 10") || platformEmulator.startsWith("Fedora 9") || platformEmulator.startsWith("CentOS 5.3") || platformEmulator.startsWith("CentOS 5.4") ||
3008+
platformEmulator.startsWith("CentOS 5.5") || platformEmulator.startsWith("CentOS") || platformEmulator.startsWith("Fedora") ||
3009+
platformEmulator.startsWith("Red Hat Enterprise Linux 5.3") || platformEmulator.startsWith("Red Hat Enterprise Linux 5.4") ||
3010+
platformEmulator.startsWith("Red Hat Enterprise Linux 5.5") || platformEmulator.startsWith("Red Hat Enterprise Linux 6") || platformEmulator.startsWith("Debian GNU/Linux") ||
3011+
platformEmulator.startsWith("FreeBSD 10") || platformEmulator.startsWith("Oracle") || platformEmulator.startsWith("Other PV")) {
29893012
return DiskDef.DiskBus.VIRTIO;
29903013
} else {
29913014
return DiskDef.DiskBus.IDE;
29923015
}
2993-
}
29943016

3017+
}
29953018
private void cleanupVMNetworks(final Connect conn, final List<InterfaceDef> nics) {
29963019
if (nics != null) {
29973020
for (final InterfaceDef nic : nics) {

plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,6 +1345,37 @@ public String toString() {
13451345
}
13461346
}
13471347

1348+
public static class SCSIDef {
1349+
private short index = 0;
1350+
private int domain = 0;
1351+
private int bus = 0;
1352+
private int slot = 9;
1353+
private int function = 0;
1354+
1355+
public SCSIDef(short index, int domain, int bus, int slot, int function) {
1356+
this.index = index;
1357+
this.domain = domain;
1358+
this.bus = bus;
1359+
this.slot = slot;
1360+
this.function = function;
1361+
}
1362+
1363+
public SCSIDef() {
1364+
1365+
}
1366+
1367+
@Override
1368+
public String toString() {
1369+
StringBuilder scsiBuilder = new StringBuilder();
1370+
1371+
scsiBuilder.append(String.format("<controller type='scsi' index='%d' mode='virtio-scsi'>\n", this.index ));
1372+
scsiBuilder.append(String.format("<address type='pci' domain='0x%04X' bus='0x%02X' slot='0x%02X' function='0x%01X'/>\n",
1373+
this.domain, this.bus, this.slot, this.function ) );
1374+
scsiBuilder.append("</controller>");
1375+
return scsiBuilder.toString();
1376+
}
1377+
}
1378+
13481379
public static class InputDef {
13491380
private final String _type; /* tablet, mouse */
13501381
private final String _bus; /* ps2, usb, xen */

plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
import com.cloud.hypervisor.kvm.resource.LibvirtConnection;
8989
import com.cloud.hypervisor.kvm.resource.LibvirtDomainXMLParser;
9090
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
91+
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef.DeviceType;
9192
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef.DiskProtocol;
9293
import com.cloud.storage.JavaStorageLayer;
9394
import com.cloud.storage.Storage.ImageFormat;
@@ -972,13 +973,12 @@ protected synchronized String attachOrDetachDisk(final Connect conn, final boole
972973
DiskDef diskdef = null;
973974
final KVMStoragePool attachingPool = attachingDisk.getPool();
974975
try {
976+
dm = conn.domainLookupByName(vmName);
977+
final LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
978+
final String domXml = dm.getXMLDesc(0);
979+
parser.parseDomainXML(domXml);
980+
disks = parser.getDisks();
975981
if (!attach) {
976-
dm = conn.domainLookupByName(vmName);
977-
final LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
978-
final String xml = dm.getXMLDesc(0);
979-
parser.parseDomainXML(xml);
980-
disks = parser.getDisks();
981-
982982
if (attachingPool.getType() == StoragePoolType.RBD) {
983983
if (resource.getHypervisorType() == Hypervisor.HypervisorType.LXC) {
984984
final String device = resource.mapRbdDevice(attachingDisk);
@@ -1000,6 +1000,17 @@ protected synchronized String attachOrDetachDisk(final Connect conn, final boole
10001000
throw new InternalErrorException("disk: " + attachingDisk.getPath() + " is not attached before");
10011001
}
10021002
} else {
1003+
DiskDef.DiskBus busT = DiskDef.DiskBus.VIRTIO;
1004+
for (final DiskDef disk : disks) {
1005+
s_logger.debug("disk is type : "+disk.toString());
1006+
if (disk.getDeviceType() == DeviceType.DISK) {
1007+
if (disk.getBusType() == DiskDef.DiskBus.SCSI) {
1008+
busT = DiskDef.DiskBus.SCSI;
1009+
}
1010+
s_logger.debug("Disk bus type: " + disk.getDeviceType().toString() + ", busT: "+busT.toString());
1011+
break;
1012+
}
1013+
}
10031014
diskdef = new DiskDef();
10041015
diskdef.setSerial(serial);
10051016
if (attachingPool.getType() == StoragePoolType.RBD) {
@@ -1008,24 +1019,24 @@ protected synchronized String attachOrDetachDisk(final Connect conn, final boole
10081019
final String device = resource.mapRbdDevice(attachingDisk);
10091020
if (device != null) {
10101021
s_logger.debug("RBD device on host is: "+device);
1011-
diskdef.defBlockBasedDisk(device, devId, DiskDef.DiskBus.VIRTIO);
1022+
diskdef.defBlockBasedDisk(device, devId, busT);
10121023
} else {
10131024
throw new InternalErrorException("Error while mapping disk "+attachingDisk.getPath()+" on host");
10141025
}
10151026
} else {
10161027
diskdef.defNetworkBasedDisk(attachingDisk.getPath(), attachingPool.getSourceHost(), attachingPool.getSourcePort(), attachingPool.getAuthUserName(),
1017-
attachingPool.getUuid(), devId, DiskDef.DiskBus.VIRTIO, DiskProtocol.RBD, DiskDef.DiskFmtType.RAW);
1028+
attachingPool.getUuid(), devId, busT, DiskProtocol.RBD, DiskDef.DiskFmtType.RAW);
10181029
}
10191030
} else if (attachingPool.getType() == StoragePoolType.Gluster) {
10201031
final String mountpoint = attachingPool.getLocalPath();
10211032
final String path = attachingDisk.getPath();
10221033
final String glusterVolume = attachingPool.getSourceDir().replace("/", "");
10231034
diskdef.defNetworkBasedDisk(glusterVolume + path.replace(mountpoint, ""), attachingPool.getSourceHost(), attachingPool.getSourcePort(), null,
1024-
null, devId, DiskDef.DiskBus.VIRTIO, DiskProtocol.GLUSTER, DiskDef.DiskFmtType.QCOW2);
1035+
null, devId, busT, DiskProtocol.GLUSTER, DiskDef.DiskFmtType.QCOW2);
10251036
} else if (attachingDisk.getFormat() == PhysicalDiskFormat.QCOW2) {
1026-
diskdef.defFileBasedDisk(attachingDisk.getPath(), devId, DiskDef.DiskBus.VIRTIO, DiskDef.DiskFmtType.QCOW2);
1037+
diskdef.defFileBasedDisk(attachingDisk.getPath(), devId, busT, DiskDef.DiskFmtType.QCOW2);
10271038
} else if (attachingDisk.getFormat() == PhysicalDiskFormat.RAW) {
1028-
diskdef.defBlockBasedDisk(attachingDisk.getPath(), devId, DiskDef.DiskBus.VIRTIO);
1039+
diskdef.defBlockBasedDisk(attachingDisk.getPath(), devId, busT);
10291040
}
10301041

10311042
if ((bytesReadRate != null) && (bytesReadRate > 0)) {

setup/db/db/schema-4920to41000.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ INSERT IGNORE INTO `cloud`.`guest_os` (id, uuid, category_id, display_name, crea
3939
INSERT IGNORE INTO `cloud`.`guest_os` (id, uuid, category_id, display_name, created) VALUES (272, UUID(), 4, 'Red Hat Enterprise Linux 7.1', now());
4040
INSERT IGNORE INTO `cloud`.`guest_os` (id, uuid, category_id, display_name, created) VALUES (273, UUID(), 4, 'Red Hat Enterprise Linux 7.2', now());
4141
INSERT IGNORE INTO `cloud`.`guest_os` (id, uuid, category_id, display_name, created) VALUES (274, UUID(), 1, 'CentOS 7.2', now());
42+
INSERT IGNORE INTO `cloud`.`guest_os` (id, uuid, category_id, display_name, created) VALUES (275, UUID(), 6, 'Other PV Virtio-SCSI (64-bit)', now());
4243

4344
INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid, hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'Xenserver', '6.5.0', 'Windows 10 (32-bit)', 257, now(), 0);
4445
INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid, hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '6.0', 'windows9Guest', 257, now(), 0);
@@ -108,6 +109,7 @@ INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid, hypervisor_type, hypervi
108109
INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid, hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centos64Guest', 274, now(), 0);
109110
INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid, hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '6.0', 'centos64Guest', 274, now(), 0);
110111
INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid, hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'KVM', 'default', 'CentOS 7.2', 274, now(), 0);
112+
INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid, hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'KVM', 'default', 'Other PV Virtio-SCSI (64-bit)', 275, now(), 0);
111113

112114
CREATE TABLE `cloud`.`vlan_details` (
113115
`id` bigint unsigned NOT NULL auto_increment,

0 commit comments

Comments
 (0)