mirror of
https://github.com/apache/cloudstack.git
synced 2025-11-03 04:12:31 +01:00
Merge pull request #1572 from wido/virtio-rng
CLOUDSTACK-9395: Add Virtio RNG device to Instances when configuredBy adding a Random Number Generator device to Instances we can prevent
entropy starvation inside guest.
The default source is /dev/random on the host, but this can be configured
to another source when present, for example a hardware RNG.
When enabled it will add the following to the Instance's XML definition:
<rng model='virtio'>
<backend model='random'>/dev/random</backend>
</rng>
If the Instance has the proper support, which most modern distributions have,
it will have a /dev/hwrng device which it can use for gathering entropy.
* pr/1572:
CLOUDSTACK-9395: Add Virtio RNG device to Instances when configured
Signed-off-by: Rajani Karuturi <rajani.karuturi@accelerite.com>
This commit is contained in:
commit
c9e14c9f08
@ -152,3 +152,22 @@ hypervisor.type=kvm
|
|||||||
# kvmclock.disable=false
|
# kvmclock.disable=false
|
||||||
# Some newer linux kernels are incapable of reliably migrating vms with kvmclock
|
# 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
|
# 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.
|
||||||
|
|||||||
@ -44,6 +44,7 @@ import java.util.regex.Pattern;
|
|||||||
import javax.ejb.Local;
|
import javax.ejb.Local;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
|
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
|
||||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||||
import org.apache.cloudstack.utils.hypervisor.HypervisorUtils;
|
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.TermPolicy;
|
||||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.VideoDef;
|
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.VideoDef;
|
||||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.VirtioSerialDef;
|
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.LibvirtRequestWrapper;
|
||||||
import com.cloud.hypervisor.kvm.resource.wrapper.LibvirtUtilitiesHelper;
|
import com.cloud.hypervisor.kvm.resource.wrapper.LibvirtUtilitiesHelper;
|
||||||
import com.cloud.hypervisor.kvm.storage.KVMPhysicalDisk;
|
import com.cloud.hypervisor.kvm.storage.KVMPhysicalDisk;
|
||||||
@ -244,6 +247,11 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
protected long _diskActivityCheckFileSizeMin = 10485760; // 10MB
|
protected long _diskActivityCheckFileSizeMin = 10485760; // 10MB
|
||||||
protected int _diskActivityCheckTimeoutSeconds = 120; // 120s
|
protected int _diskActivityCheckTimeoutSeconds = 120; // 120s
|
||||||
protected long _diskActivityInactiveThresholdMilliseconds = 30000; // 30s
|
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 <String, String> _pifs = new HashMap<String, String>();
|
private final Map <String, String> _pifs = new HashMap<String, String>();
|
||||||
private final Map<String, VmStats> _vmStats = new ConcurrentHashMap<String, VmStats>();
|
private final Map<String, VmStats> _vmStats = new ConcurrentHashMap<String, VmStats>();
|
||||||
@ -803,6 +811,27 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
_noKvmClock = true;
|
_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);
|
LibvirtConnection.initialize(_hypervisorURI);
|
||||||
Connect conn = null;
|
Connect conn = null;
|
||||||
try {
|
try {
|
||||||
@ -1983,6 +2012,11 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||||||
devices.addDevice(vserial);
|
devices.addDevice(vserial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_rngEnable) {
|
||||||
|
final RngDef rngDevice = new RngDef(_rngPath, _rngBackendModel, _rngRateBytes, _rngRatePeriod);
|
||||||
|
devices.addDevice(rngDevice);
|
||||||
|
}
|
||||||
|
|
||||||
final VideoDef videoCard = new VideoDef(_videoHw, _videoRam);
|
final VideoDef videoCard = new VideoDef(_videoHw, _videoRam);
|
||||||
devices.addDevice(videoCard);
|
devices.addDevice(videoCard);
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import javax.xml.parsers.DocumentBuilder;
|
|||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
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.DiskDef;
|
||||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
|
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
|
||||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef.NicModel;
|
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 {
|
public class LibvirtDomainXMLParser {
|
||||||
private static final Logger s_logger = Logger.getLogger(LibvirtDomainXMLParser.class);
|
private static final Logger s_logger = Logger.getLogger(LibvirtDomainXMLParser.class);
|
||||||
private final List<InterfaceDef> interfaces = new ArrayList<InterfaceDef>();
|
private final List<InterfaceDef> interfaces = new ArrayList<InterfaceDef>();
|
||||||
private final List<DiskDef> diskDefs = new ArrayList<DiskDef>();
|
private final List<DiskDef> diskDefs = new ArrayList<DiskDef>();
|
||||||
|
private final List<RngDef> rngDefs = new ArrayList<RngDef>();
|
||||||
private Integer vncPort;
|
private Integer vncPort;
|
||||||
private String desc;
|
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;
|
return true;
|
||||||
} catch (ParserConfigurationException e) {
|
} catch (ParserConfigurationException e) {
|
||||||
s_logger.debug(e.toString());
|
s_logger.debug(e.toString());
|
||||||
@ -234,6 +257,10 @@ public class LibvirtDomainXMLParser {
|
|||||||
return diskDefs;
|
return diskDefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<RngDef> getRngs() {
|
||||||
|
return rngDefs;
|
||||||
|
}
|
||||||
|
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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("<rng model='" + rngModel + "'>\n");
|
||||||
|
rngBuilder.append("<rate period='" + rngRatePeriod + "' bytes='" + rngRateBytes + "' />\n");
|
||||||
|
rngBuilder.append("<backend model='" + rngBackendModel + "'>" + path + "</backend>");
|
||||||
|
rngBuilder.append("</rng>\n");
|
||||||
|
return rngBuilder.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setHvsType(String hvs) {
|
public void setHvsType(String hvs) {
|
||||||
_hvsType = hvs;
|
_hvsType = hvs;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,7 @@ import junit.framework.TestCase;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
|
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
|
||||||
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
|
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
|
||||||
|
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.RngDef;
|
||||||
|
|
||||||
public class LibvirtDomainXMLParserTest extends TestCase {
|
public class LibvirtDomainXMLParserTest extends TestCase {
|
||||||
|
|
||||||
@ -164,6 +165,10 @@ public class LibvirtDomainXMLParserTest extends TestCase {
|
|||||||
"<alias name='balloon0'/>" +
|
"<alias name='balloon0'/>" +
|
||||||
"<address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>" +
|
"<address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>" +
|
||||||
"</memballoon>" +
|
"</memballoon>" +
|
||||||
|
"<rng model='virtio'>" +
|
||||||
|
"<rate period='5000' bytes='4096' />" +
|
||||||
|
"<backend model='random'>/dev/random</backend>" +
|
||||||
|
"</rng>" +
|
||||||
"</devices>" +
|
"</devices>" +
|
||||||
"<seclabel type='none'/>" +
|
"<seclabel type='none'/>" +
|
||||||
"</domain>";
|
"</domain>";
|
||||||
@ -190,5 +195,11 @@ public class LibvirtDomainXMLParserTest extends TestCase {
|
|||||||
assertEquals(ifModel, ifs.get(i).getModel());
|
assertEquals(ifModel, ifs.get(i).getModel());
|
||||||
assertEquals(ifType, ifs.get(i).getNetType());
|
assertEquals(ifType, ifs.get(i).getNetType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<RngDef> 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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -118,4 +118,18 @@ public class LibvirtVMDefTest extends TestCase {
|
|||||||
assertTrue((hostOsVersion.first() == 6 && hostOsVersion.second() >= 5) || (hostOsVersion.first() >= 7));
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user