Skip to content

Commit b61de8d

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 6603e09 commit b61de8d

File tree

4 files changed

+102
-51
lines changed

4 files changed

+102
-51
lines changed

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

Lines changed: 48 additions & 34 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;
@@ -2015,7 +2016,7 @@ So if getMinSpeed() returns null we fall back to getSpeed().
20152016
if (vmTO.getOs().startsWith("Windows")) {
20162017
clock.setClockOffset(ClockDef.ClockOffset.LOCALTIME);
20172018
clock.setTimer("rtc", "catchup", null);
2018-
} else if (vmTO.getType() != VirtualMachine.Type.User || isGuestPVEnabled(vmTO.getOs()).equals("VIRTIO") || isGuestPVEnabled(vmTO.getOs()).equals("SCSI")) {
2019+
} else if (vmTO.getType() != VirtualMachine.Type.User || isGuestPVEnabled(vmTO.getOs())) {
20192020
if (_hypervisorLibvirtVersion >= 9 * 1000 + 10) {
20202021
clock.setTimer("kvmclock", null, null, _noKvmClock);
20212022
}
@@ -2059,6 +2060,13 @@ 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+
s_logger.debug("Adding scsi definition:\n" + sd.toString());
2068+
}
2069+
20622070
vm.addComp(devices);
20632071

20642072
return vm;
@@ -2158,6 +2166,7 @@ public int compare(final DiskTO arg0, final DiskTO arg1) {
21582166

21592167
if (diskBusType == null) {
21602168
diskBusType = getGuestDiskModel(vmSpec.getPlatformEmulator());
2169+
s_logger.debug("disk bus type derived from getPlatformEmulator: " + vmSpec.getPlatformEmulator() + ", diskbustype is: "+diskBusType.toString());
21612170
}
21622171
final DiskDef disk = new DiskDef();
21632172
if (volume.getType() == Volume.Type.ISO) {
@@ -2216,6 +2225,8 @@ public int compare(final DiskTO arg0, final DiskTO arg1) {
22162225
disk.setCacheMode(DiskDef.DiskCacheMode.valueOf(volumeObjectTO.getCacheMode().toString().toUpperCase()));
22172226
}
22182227
}
2228+
2229+
s_logger.debug("Adding disk: " + disk.toString());
22192230
vm.getDevices().addDevice(disk);
22202231
}
22212232

@@ -2334,13 +2345,13 @@ public synchronized String attachOrDetachDisk(final Connect conn,
23342345
DiskDef diskdef = null;
23352346
final KVMStoragePool attachingPool = attachingDisk.getPool();
23362347
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();
2348+
dm = conn.domainLookupByName(vmName);
2349+
final LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
2350+
final String domXml = dm.getXMLDesc(0);
2351+
parser.parseDomainXML(domXml);
2352+
disks = parser.getDisks();
23432353

2354+
if (!attach) {
23442355
for (final DiskDef disk : disks) {
23452356
final String file = disk.getDiskPath();
23462357
if (file != null && file.equalsIgnoreCase(attachingDisk.getPath())) {
@@ -2352,17 +2363,29 @@ public synchronized String attachOrDetachDisk(final Connect conn,
23522363
throw new InternalErrorException("disk: " + attachingDisk.getPath() + " is not attached before");
23532364
}
23542365
} else {
2366+
DiskDef.DiskBus busT = DiskDef.DiskBus.VIRTIO;
2367+
for (final DiskDef disk : disks) {
2368+
s_logger.debug("disk is type : "+disk.toString());
2369+
if (disk.getDeviceType() == DeviceType.DISK) {
2370+
if (disk.getBusType() == DiskDef.DiskBus.SCSI) {
2371+
busT = DiskDef.DiskBus.SCSI;
2372+
}
2373+
s_logger.debug("Disk bus type: " + disk.getDeviceType().toString() + ", busT: "+busT.toString());
2374+
break;
2375+
}
2376+
}
2377+
23552378
diskdef = new DiskDef();
23562379
if (attachingPool.getType() == StoragePoolType.RBD) {
23572380
diskdef.defNetworkBasedDisk(attachingDisk.getPath(), attachingPool.getSourceHost(), attachingPool.getSourcePort(), attachingPool.getAuthUserName(),
2358-
attachingPool.getUuid(), devId, DiskDef.DiskBus.VIRTIO, DiskProtocol.RBD, DiskDef.DiskFmtType.RAW);
2381+
attachingPool.getUuid(), devId, busT, DiskProtocol.RBD, DiskDef.DiskFmtType.RAW);
23592382
} else if (attachingPool.getType() == StoragePoolType.Gluster) {
23602383
diskdef.defNetworkBasedDisk(attachingDisk.getPath(), attachingPool.getSourceHost(), attachingPool.getSourcePort(), null,
2361-
null, devId, DiskDef.DiskBus.VIRTIO, DiskProtocol.GLUSTER, DiskDef.DiskFmtType.QCOW2);
2384+
null, devId, busT, DiskProtocol.GLUSTER, DiskDef.DiskFmtType.QCOW2);
23622385
} else if (attachingDisk.getFormat() == PhysicalDiskFormat.QCOW2) {
2363-
diskdef.defFileBasedDisk(attachingDisk.getPath(), devId, DiskDef.DiskBus.VIRTIO, DiskDef.DiskFmtType.QCOW2);
2386+
diskdef.defFileBasedDisk(attachingDisk.getPath(), devId, busT, DiskDef.DiskFmtType.QCOW2);
23642387
} else if (attachingDisk.getFormat() == PhysicalDiskFormat.RAW) {
2365-
diskdef.defBlockBasedDisk(attachingDisk.getPath(), devId, DiskDef.DiskBus.VIRTIO);
2388+
diskdef.defBlockBasedDisk(attachingDisk.getPath(), devId, busT);
23662389
}
23672390
if (bytesReadRate != null && bytesReadRate > 0) {
23682391
diskdef.setBytesReadRate(bytesReadRate);
@@ -2960,23 +2983,9 @@ private String getHypervisorPath(final Connect conn) {
29602983
return parser.getEmulator();
29612984
}
29622985

2963-
private String isGuestPVEnabled(final String guestOSName) {
2964-
if (guestOSName == null) {
2965-
return "IDE";
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 "VIRTIO";
2974-
}
2975-
else if (guestOSName.startsWith("Other PV Virtio-SCSI")) {
2976-
return "SCSI";
2977-
} else {
2978-
return "IDE:";
2979-
}
2986+
boolean isGuestPVEnabled(final String guestOSName) {
2987+
DiskDef.DiskBus db = getGuestDiskModel(guestOSName);
2988+
return db != DiskDef.DiskBus.IDE;
29802989
}
29812990

29822991
public boolean isCentosHost() {
@@ -2988,17 +2997,22 @@ public boolean isCentosHost() {
29882997
}
29892998

29902999
private DiskDef.DiskBus getGuestDiskModel(final String platformEmulator) {
2991-
if (isGuestPVEnabled(platformEmulator).equals("VIRTIO")) {
2992-
return DiskDef.DiskBus.VIRTIO;
2993-
} else if(isGuestPVEnabled(platformEmulator).equals("SCSI")) {
2994-
return DiskDef.DiskBus.SCSI;
2995-
} else if(isGuestPVEnabled(platformEmulator).equals("IDE")) {
3000+
if (platformEmulator == null) {
29963001
return DiskDef.DiskBus.IDE;
3002+
} else if (platformEmulator.startsWith("Other PV Virtio-SCSI")) {
3003+
return DiskDef.DiskBus.SCSI;
3004+
} else if (platformEmulator.startsWith("Ubuntu") || platformEmulator.startsWith("Fedora 13") || platformEmulator.startsWith("Fedora 12") || platformEmulator.startsWith("Fedora 11") ||
3005+
platformEmulator.startsWith("Fedora 10") || platformEmulator.startsWith("Fedora 9") || platformEmulator.startsWith("CentOS 5.3") || platformEmulator.startsWith("CentOS 5.4") ||
3006+
platformEmulator.startsWith("CentOS 5.5") || platformEmulator.startsWith("CentOS") || platformEmulator.startsWith("Fedora") ||
3007+
platformEmulator.startsWith("Red Hat Enterprise Linux 5.3") || platformEmulator.startsWith("Red Hat Enterprise Linux 5.4") ||
3008+
platformEmulator.startsWith("Red Hat Enterprise Linux 5.5") || platformEmulator.startsWith("Red Hat Enterprise Linux 6") || platformEmulator.startsWith("Debian GNU/Linux") ||
3009+
platformEmulator.startsWith("FreeBSD 10") || platformEmulator.startsWith("Oracle") || platformEmulator.startsWith("Other PV")) {
3010+
return DiskDef.DiskBus.VIRTIO;
29973011
} else {
29983012
return DiskDef.DiskBus.IDE;
29993013
}
3000-
}
30013014

3015+
}
30023016
private void cleanupVMNetworks(final Connect conn, final List<InterfaceDef> nics) {
30033017
if (nics != null) {
30043018
for (final InterfaceDef nic : nics) {

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

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -828,11 +828,6 @@ public String toString() {
828828
}
829829

830830
diskBuilder.append("</disk>\n");
831-
if (_bus == DiskBus.SCSI) {
832-
diskBuilder.append("<controller type='scsi' index='0' model='virtio-scsi'>\n");
833-
diskBuilder.append("<address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>\n");
834-
diskBuilder.append("</controller>");
835-
}
836831
return diskBuilder.toString();
837832
}
838833
}
@@ -1350,6 +1345,37 @@ public String toString() {
13501345
}
13511346
}
13521347

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+
13531379
public static class InputDef {
13541380
private final String _type; /* tablet, mouse */
13551381
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: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid, hypervisor_type, hypervi
109109
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);
110110
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);
111111
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) VALUES (UUID(), 'KVM', 'default', 'Other PV Virtio-SCSI (64-bit)', 260, now());
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);
113113

114114
CREATE TABLE `cloud`.`vlan_details` (
115115
`id` bigint unsigned NOT NULL auto_increment,

0 commit comments

Comments
 (0)