diff --git a/agent/conf/agent.properties b/agent/conf/agent.properties index daad05f3b65..1a3412e8e31 100644 --- a/agent/conf/agent.properties +++ b/agent/conf/agent.properties @@ -152,3 +152,22 @@ hypervisor.type=kvm # kvmclock.disable=false # Some newer linux kernels are incapable of reliably migrating vms with kvmclock # This is a workaround for the bug, admin can set this to true per-host +# +# vm.rng.enable=false +# This enabled the VirtIO Random Number Generator device for guests. +# +# vm.rng.model=random +# The model of VirtIO Random Number Generator (RNG) to present to the Guest. +# Currently only 'random' is supported. +# +# vm.rng.path=/dev/random +# Local Random Number Device Generator to use for VirtIO RNG for Guests. +# This is usually /dev/random, but per platform this might be different +# +# vm.rng.rate.bytes=2048 +# The amount of bytes the Guest may request/obtain from the RNG in the period +# specified below. +# +# vm.rng.rate.period=1000 +# The number of milliseconds in which the guest is allowed to obtain the bytes +# specified above. diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 2b9aa71cf2f..53fb9c9f4be 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -44,6 +44,7 @@ import java.util.regex.Pattern; import javax.ejb.Local; import javax.naming.ConfigurationException; +import com.google.common.base.Strings; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.cloudstack.utils.hypervisor.HypervisorUtils; @@ -115,6 +116,8 @@ import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.SerialDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.TermPolicy; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.VideoDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.VirtioSerialDef; +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.RngDef; +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.RngDef.RngBackendModel; import com.cloud.hypervisor.kvm.resource.wrapper.LibvirtRequestWrapper; import com.cloud.hypervisor.kvm.resource.wrapper.LibvirtUtilitiesHelper; import com.cloud.hypervisor.kvm.storage.KVMPhysicalDisk; @@ -244,6 +247,11 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv protected long _diskActivityCheckFileSizeMin = 10485760; // 10MB protected int _diskActivityCheckTimeoutSeconds = 120; // 120s protected long _diskActivityInactiveThresholdMilliseconds = 30000; // 30s + protected boolean _rngEnable = false; + protected RngBackendModel _rngBackendModel = RngBackendModel.RANDOM; + protected String _rngPath = "/dev/random"; + protected int _rngRatePeriod = 1000; + protected int _rngRateBytes = 2048; private final Map _pifs = new HashMap(); private final Map _vmStats = new ConcurrentHashMap(); @@ -803,6 +811,27 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv _noKvmClock = true; } + value = (String) params.get("vm.rng.enable"); + if (Boolean.parseBoolean(value)) { + _rngEnable = true; + + value = (String) params.get("vm.rng.model"); + if (!Strings.isNullOrEmpty(value)) { + _rngBackendModel = RngBackendModel.valueOf(value.toUpperCase()); + } + + value = (String) params.get("vm.rng.path"); + if (!Strings.isNullOrEmpty(value)) { + _rngPath = value; + } + + value = (String) params.get("vm.rng.rate.bytes"); + _rngRateBytes = NumbersUtil.parseInt(value, new Integer(_rngRateBytes)); + + value = (String) params.get("vm.rng.rate.period"); + _rngRatePeriod = NumbersUtil.parseInt(value, new Integer(_rngRatePeriod)); + } + LibvirtConnection.initialize(_hypervisorURI); Connect conn = null; try { @@ -1983,6 +2012,11 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv devices.addDevice(vserial); } + if (_rngEnable) { + final RngDef rngDevice = new RngDef(_rngPath, _rngBackendModel, _rngRateBytes, _rngRatePeriod); + devices.addDevice(rngDevice); + } + final VideoDef videoCard = new VideoDef(_videoHw, _videoRam); devices.addDevice(videoCard); diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java index 0b6b9d989c8..b77c1c84f49 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java @@ -25,6 +25,7 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import com.google.common.base.Strings; import org.apache.log4j.Logger; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -36,11 +37,14 @@ import org.xml.sax.SAXException; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef.NicModel; +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.RngDef; +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.RngDef.RngBackendModel; public class LibvirtDomainXMLParser { private static final Logger s_logger = Logger.getLogger(LibvirtDomainXMLParser.class); private final List interfaces = new ArrayList(); private final List diskDefs = new ArrayList(); + private final List rngDefs = new ArrayList(); private Integer vncPort; private String desc; @@ -189,6 +193,25 @@ public class LibvirtDomainXMLParser { } } + NodeList rngs = devices.getElementsByTagName("rng"); + for (int i = 0; i < rngs.getLength(); i++) { + RngDef def = null; + Element rng = (Element)rngs.item(i); + String backendModel = getAttrValue("backend", "model", rng); + String path = getTagValue("backend", rng); + String bytes = getAttrValue("rate", "bytes", rng); + String period = getAttrValue("rate", "period", rng); + + if (Strings.isNullOrEmpty(backendModel)) { + def = new RngDef(path, Integer.parseInt(bytes), Integer.parseInt(period)); + } else { + def = new RngDef(path, RngBackendModel.valueOf(backendModel.toUpperCase()), + Integer.parseInt(bytes), Integer.parseInt(period)); + } + + rngDefs.add(def); + } + return true; } catch (ParserConfigurationException e) { s_logger.debug(e.toString()); @@ -234,6 +257,10 @@ public class LibvirtDomainXMLParser { return diskDefs; } + public List getRngs() { + return rngDefs; + } + public String getDescription() { return desc; } diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java index 6ce7d6c8f5e..157d7112ae2 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java @@ -1366,6 +1366,107 @@ public class LibvirtVMDef { } } + public static class RngDef { + enum RngModel { + VIRTIO("virtio"); + String model; + + RngModel(String model) { + this.model = model; + } + + @Override + public String toString() { + return model; + } + } + + enum RngBackendModel { + RANDOM("random"), EGD("egd"); + String model; + + RngBackendModel(String model) { + this.model = model; + } + + @Override + public String toString() { + return model; + } + } + + private String path = "/dev/random"; + private RngModel rngModel = RngModel.VIRTIO; + private RngBackendModel rngBackendModel = RngBackendModel.RANDOM; + private int rngRateBytes = 2048; + private int rngRatePeriod = 1000; + + public RngDef(String path) { + this.path = path; + } + + public RngDef(String path, int rngRateBytes, int rngRatePeriod) { + this.path = path; + this.rngRateBytes = rngRateBytes; + this.rngRatePeriod = rngRatePeriod; + } + + public RngDef(RngModel rngModel) { + this.rngModel = rngModel; + } + + public RngDef(RngBackendModel rngBackendModel) { + this.rngBackendModel = rngBackendModel; + } + + public RngDef(String path, RngBackendModel rngBackendModel) { + this.path = path; + this.rngBackendModel = rngBackendModel; + } + + public RngDef(String path, RngBackendModel rngBackendModel, int rngRateBytes, int rngRatePeriod) { + this.path = path; + this.rngBackendModel = rngBackendModel; + this.rngRateBytes = rngRateBytes; + this.rngRatePeriod = rngRatePeriod; + } + + public RngDef(String path, RngModel rngModel) { + this.path = path; + this.rngModel = rngModel; + } + + public String getPath() { + return path; + } + + public RngBackendModel getRngBackendModel() { + return rngBackendModel; + } + + public RngModel getRngModel() { + return rngModel; + } + + public int getRngRateBytes() { + return rngRateBytes; + } + + public int getRngRatePeriod() { + return rngRatePeriod; + } + + @Override + public String toString() { + StringBuilder rngBuilder = new StringBuilder(); + rngBuilder.append("\n"); + rngBuilder.append("\n"); + rngBuilder.append("" + path + ""); + rngBuilder.append("\n"); + return rngBuilder.toString(); + } + } + public void setHvsType(String hvs) { _hvsType = hvs; } diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java index eb28d8b9d9f..a71232cd06f 100644 --- a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java +++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java @@ -23,6 +23,7 @@ import junit.framework.TestCase; import java.util.List; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef; +import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.RngDef; public class LibvirtDomainXMLParserTest extends TestCase { @@ -164,6 +165,10 @@ public class LibvirtDomainXMLParserTest extends TestCase { "" + "
" + "" + + "" + + "" + + "/dev/random" + + "" + "" + "" + ""; @@ -190,5 +195,11 @@ public class LibvirtDomainXMLParserTest extends TestCase { assertEquals(ifModel, ifs.get(i).getModel()); assertEquals(ifType, ifs.get(i).getNetType()); } + + List rngs = parser.getRngs(); + assertEquals("/dev/random", rngs.get(0).getPath()); + assertEquals(RngDef.RngBackendModel.RANDOM, rngs.get(0).getRngBackendModel()); + assertEquals(4096, rngs.get(0).getRngRateBytes()); + assertEquals(5000, rngs.get(0).getRngRatePeriod()); } -} \ No newline at end of file +} diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java index a9261291a02..f0d1b5b9a39 100644 --- a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java +++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java @@ -118,4 +118,18 @@ public class LibvirtVMDefTest extends TestCase { assertTrue((hostOsVersion.first() == 6 && hostOsVersion.second() >= 5) || (hostOsVersion.first() >= 7)); } + public void testChannelDef() { + LibvirtVMDef.RngDef.RngBackendModel backendModel = LibvirtVMDef.RngDef.RngBackendModel.RANDOM; + String path = "/dev/random"; + int period = 2000; + int bytes = 2048; + + LibvirtVMDef.RngDef def = new LibvirtVMDef.RngDef(path, backendModel, bytes, period); + assertEquals(def.getPath(), path); + assertEquals(def.getRngBackendModel(), backendModel); + assertEquals(def.getRngModel(), LibvirtVMDef.RngDef.RngModel.VIRTIO); + assertEquals(def.getRngRateBytes(), bytes); + assertEquals(def.getRngRatePeriod(), period); + } + }