diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 13c4141528..17c9e26210 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -175,7 +175,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST, "redirdev", "smartcard", "chr", - "memballoon") + "memballoon", + "rng") VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST, "none", @@ -700,6 +701,15 @@ VIR_ENUM_IMPL(virDomainNumatuneMemPlacementMode, "static", "auto"); +VIR_ENUM_IMPL(virDomainRNGModel, + VIR_DOMAIN_RNG_MODEL_LAST, + "virtio"); + +VIR_ENUM_IMPL(virDomainRNGBackend, + VIR_DOMAIN_RNG_BACKEND_LAST, + "random", + "egd"); + #define VIR_DOMAIN_XML_WRITE_FLAGS VIR_DOMAIN_XML_SECURE #define VIR_DOMAIN_XML_READ_FLAGS VIR_DOMAIN_XML_INACTIVE @@ -1597,6 +1607,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def) case VIR_DOMAIN_DEVICE_REDIRDEV: virDomainRedirdevDefFree(def->data.redirdev); break; + case VIR_DOMAIN_DEVICE_RNG: + virDomainRNGDefFree(def->data.rng); + break; case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_FS: case VIR_DOMAIN_DEVICE_SMARTCARD: @@ -2342,6 +2355,12 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def, if (cb(def, &device, &def->memballoon->info, opaque) < 0) return -1; } + if (def->rng) { + device.type = VIR_DOMAIN_DEVICE_RNG; + device.data.rng = def->rng; + if (cb(def, &device, &def->rng->info, opaque) < 0) + return -1; + } device.type = VIR_DOMAIN_DEVICE_HUB; for (i = 0; i < def->nhubs ; i++) { device.data.hub = def->hubs[i]; @@ -2374,6 +2393,7 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def, case VIR_DOMAIN_DEVICE_CHR: case VIR_DOMAIN_DEVICE_MEMBALLOON: case VIR_DOMAIN_DEVICE_LAST: + case VIR_DOMAIN_DEVICE_RNG: break; } @@ -7452,6 +7472,110 @@ error: } +static virDomainRNGDefPtr +virDomainRNGDefParseXML(const xmlNodePtr node, + xmlXPathContextPtr ctxt, + unsigned int flags) +{ + const char *model = NULL; + const char *backend = NULL; + const char *type = NULL; + virDomainRNGDefPtr def; + xmlNodePtr save = ctxt->node; + xmlNodePtr *backends = NULL; + int nbackends; + + if (VIR_ALLOC(def) < 0) { + virReportOOMError(); + return NULL; + } + + if (!(model = virXMLPropString(node, "model"))) { + virReportError(VIR_ERR_XML_ERROR, "%s", _("missing RNG device model")); + goto error; + } + + if ((def->model = virDomainRNGModelTypeFromString(model)) < 0) { + virReportError(VIR_ERR_XML_ERROR, _("unknown RNG model '%s'"), model); + goto error; + } + + ctxt->node = node; + + if ((nbackends = virXPathNodeSet("./backend", ctxt, &backends)) < 0) + goto error; + + if (nbackends != 1) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("only one RNG backend is supported")); + goto error; + } + + if (!(backend = virXMLPropString(backends[0], "model"))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing RNG device backend model")); + goto error; + } + + if ((def->backend = virDomainRNGBackendTypeFromString(backend)) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("unknown RNG backend model '%s'"), backend); + goto error; + } + + switch ((enum virDomainRNGBackend) def->backend) { + case VIR_DOMAIN_RNG_BACKEND_RANDOM: + def->source.file = virXPathString("string(./backend)", ctxt); + break; + + case VIR_DOMAIN_RNG_BACKEND_EGD: + if (!(type = virXMLPropString(backends[0], "type"))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing EGD backend type")); + goto error; + } + + if (VIR_ALLOC(def->source.chardev) < 0) { + virReportOOMError(); + goto error; + } + + def->source.chardev->type = virDomainChrTypeFromString(type); + if (def->source.chardev->type < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("unknown backend type '%s' for egd"), + type); + goto error; + } + + if (virDomainChrSourceDefParseXML(def->source.chardev, + backends[0]->children, flags, + NULL, ctxt, NULL, 0) < 0) + goto error; + break; + + case VIR_DOMAIN_RNG_BACKEND_LAST: + break; + } + + if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0) + goto error; + +cleanup: + VIR_FREE(model); + VIR_FREE(backend); + VIR_FREE(type); + VIR_FREE(backends); + ctxt->node = save; + return def; + +error: + virDomainRNGDefFree(def); + def = NULL; + goto cleanup; +} + + static virDomainMemballoonDefPtr virDomainMemballoonDefParseXML(const xmlNodePtr node, unsigned int flags) @@ -8249,6 +8373,10 @@ virDomainDeviceDefParse(virCapsPtr caps, dev->type = VIR_DOMAIN_DEVICE_REDIRDEV; if (!(dev->data.redirdev = virDomainRedirdevDefParseXML(node, NULL, flags))) goto error; + } else if (xmlStrEqual(node->name, BAD_CAST "rng")) { + dev->type = VIR_DOMAIN_DEVICE_RNG; + if (!(dev->data.rng = virDomainRNGDefParseXML(node, ctxt, flags))) + goto error; } else { virReportError(VIR_ERR_XML_ERROR, "%s", _("unknown device type")); @@ -10603,6 +10731,22 @@ virDomainDefParseXML(virCapsPtr caps, } } + /* Parse the RNG device */ + if ((n = virXPathNodeSet("./devices/rng", ctxt, &nodes)) < 0) + goto error; + + if (n > 1) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("only a single RNG device is supported")); + goto error; + } + + if (n > 0) { + if (!(def->rng = virDomainRNGDefParseXML(nodes[0], ctxt, flags))) + goto error; + VIR_FREE(nodes); + } + /* analysis of the hub devices */ if ((n = virXPathNodeSet("./devices/hub", ctxt, &nodes)) < 0) { goto error; @@ -13625,6 +13769,63 @@ virDomainWatchdogDefFormat(virBufferPtr buf, } +static int +virDomainRNGDefFormat(virBufferPtr buf, + virDomainRNGDefPtr def, + unsigned int flags) +{ + const char *model = virDomainRNGModelTypeToString(def->model); + const char *backend = virDomainRNGBackendTypeToString(def->backend); + + virBufferAsprintf(buf, " \n", model); + virBufferAsprintf(buf, " backend) { + case VIR_DOMAIN_RNG_BACKEND_RANDOM: + if (def->source.file) + virBufferEscapeString(buf, ">%s\n", def->source.file); + else + virBufferAddLit(buf, "/>\n"); + + break; + + case VIR_DOMAIN_RNG_BACKEND_EGD: + virBufferAdjustIndent(buf, 2); + if (virDomainChrSourceDefFormat(buf, def->source.chardev, + false, flags) < 0) + return -1; + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, " \n"); + + case VIR_DOMAIN_RNG_BACKEND_LAST: + break; + } + + virBufferAddLit(buf, " \n"); + + return 0; +} + +void +virDomainRNGDefFree(virDomainRNGDefPtr def) +{ + if (!def) + return; + + switch ((enum virDomainRNGBackend) def->backend) { + case VIR_DOMAIN_RNG_BACKEND_RANDOM: + VIR_FREE(def->source.file); + break; + case VIR_DOMAIN_RNG_BACKEND_EGD: + virDomainChrSourceDefFree(def->source.chardev); + break; + case VIR_DOMAIN_RNG_BACKEND_LAST: + break; + } + + VIR_FREE(def); +} + static void virDomainVideoAccelDefFormat(virBufferPtr buf, virDomainVideoAccelDefPtr def) @@ -14818,6 +15019,9 @@ virDomainDefFormatInternal(virDomainDefPtr def, if (def->memballoon) virDomainMemballoonDefFormat(buf, def->memballoon, flags); + if (def->rng) + virDomainRNGDefFormat(buf, def->rng, flags); + virBufferAddLit(buf, " \n"); virBufferAdjustIndent(buf, 2); @@ -16088,6 +16292,9 @@ virDomainDeviceDefCopy(virCapsPtr caps, case VIR_DOMAIN_DEVICE_REDIRDEV: rc = virDomainRedirdevDefFormat(&buf, src->data.redirdev, flags); break; + case VIR_DOMAIN_DEVICE_RNG: + rc = virDomainRNGDefFormat(&buf, src->data.rng, flags); + break; case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_SMARTCARD: case VIR_DOMAIN_DEVICE_CHR: diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 4ffa4aa318..0828954967 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -114,6 +114,9 @@ typedef virDomainSnapshotObj *virDomainSnapshotObjPtr; typedef struct _virDomainSnapshotObjList virDomainSnapshotObjList; typedef virDomainSnapshotObjList *virDomainSnapshotObjListPtr; +typedef struct _virDomainRNGDef virDomainRNGDef; +typedef virDomainRNGDef *virDomainRNGDefPtr; + /* Flags for the 'type' field in virDomainDeviceDef */ typedef enum { VIR_DOMAIN_DEVICE_NONE = 0, @@ -133,6 +136,7 @@ typedef enum { VIR_DOMAIN_DEVICE_SMARTCARD, VIR_DOMAIN_DEVICE_CHR, VIR_DOMAIN_DEVICE_MEMBALLOON, + VIR_DOMAIN_DEVICE_RNG, VIR_DOMAIN_DEVICE_LAST } virDomainDeviceType; @@ -158,6 +162,7 @@ struct _virDomainDeviceDef { virDomainSmartcardDefPtr smartcard; virDomainChrDefPtr chr; virDomainMemballoonDefPtr memballoon; + virDomainRNGDefPtr rng; } data; }; @@ -1714,6 +1719,33 @@ struct _virBlkioDeviceWeight { unsigned int weight; }; +enum virDomainRNGModel { + VIR_DOMAIN_RNG_MODEL_VIRTIO, + + VIR_DOMAIN_RNG_MODEL_LAST +}; + +enum virDomainRNGBackend { + VIR_DOMAIN_RNG_BACKEND_RANDOM, + VIR_DOMAIN_RNG_BACKEND_EGD, + /* VIR_DOMAIN_RNG_BACKEND_POOL, */ + + VIR_DOMAIN_RNG_BACKEND_LAST +}; + +struct _virDomainRNGDef { + int model; + int backend; + + union { + char *file; /* file name for 'random' source */ + virDomainChrSourceDefPtr chardev; /* a char backend for + the EGD source */ + } source; + + virDomainDeviceInfo info; +}; + void virBlkioDeviceWeightArrayClear(virBlkioDeviceWeightPtr deviceWeights, int ndevices); @@ -1852,6 +1884,7 @@ struct _virDomainDef { virCPUDefPtr cpu; virSysinfoDefPtr sysinfo; virDomainRedirFilterDefPtr redirfilter; + virDomainRNGDefPtr rng; void *namespaceData; virDomainXMLNamespace ns; @@ -2065,6 +2098,8 @@ int virDomainEmulatorPinAdd(virDomainDefPtr def, int virDomainEmulatorPinDel(virDomainDefPtr def); +void virDomainRNGDefFree(virDomainRNGDefPtr def); + int virDomainDiskIndexByName(virDomainDefPtr def, const char *name, bool allow_ambiguous); const char *virDomainDiskPathByName(virDomainDefPtr, const char *name); @@ -2325,6 +2360,8 @@ VIR_ENUM_DECL(virDomainGraphicsSpiceMouseMode) VIR_ENUM_DECL(virDomainNumatuneMemMode) VIR_ENUM_DECL(virDomainNumatuneMemPlacementMode) VIR_ENUM_DECL(virDomainHyperv) +VIR_ENUM_DECL(virDomainRNGModel) +VIR_ENUM_DECL(virDomainRNGBackend) /* from libvirt.h */ VIR_ENUM_DECL(virDomainState) VIR_ENUM_DECL(virDomainNostateReason) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index f399871b68..aed007e26b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -286,6 +286,8 @@ virDomainPMSuspendedReasonTypeFromString; virDomainPMSuspendedReasonTypeToString; virDomainRedirdevBusTypeFromString; virDomainRedirdevBusTypeToString; +virDomainRNGBackendTypeToString; +virDomainRNGModelTypeToString; virDomainRunningReasonTypeFromString; virDomainRunningReasonTypeToString; virDomainSaveConfig;