From 16db8d2ec540878b91994478c8b2b64d4b7b0a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Tomko?= Date: Mon, 2 Mar 2015 10:57:51 +0100 Subject: [PATCH] Add functions to track virtio-serial addresses Create a sorted array of virtio-serial controllers. Each of the elements contains the controller index and a bitmap of available ports. Buses are not tracked, because they aren't supported by QEMU. --- src/conf/domain_addr.c | 398 +++++++++++++++++++++++++++++++++++++++ src/conf/domain_addr.h | 59 ++++++ src/libvirt_private.syms | 10 + 3 files changed, 467 insertions(+) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index fb4a76fe20..49d28be887 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -718,3 +718,401 @@ virDomainCCWAddressSetCreate(void) virDomainCCWAddressSetFree(addrs); return NULL; } + + +#define VIR_DOMAIN_DEFAULT_VIRTIO_SERIAL_PORTS 31 + + +/* virDomainVirtioSerialAddrSetCreate + * + * Allocates an address set for virtio serial addresses + */ +virDomainVirtioSerialAddrSetPtr +virDomainVirtioSerialAddrSetCreate(void) +{ + virDomainVirtioSerialAddrSetPtr ret = NULL; + + if (VIR_ALLOC(ret) < 0) + return NULL; + + return ret; +} + +static void +virDomainVirtioSerialControllerFree(virDomainVirtioSerialControllerPtr cont) +{ + if (cont) { + virBitmapFree(cont->ports); + VIR_FREE(cont); + } +} + +static ssize_t +virDomainVirtioSerialAddrPlaceController(virDomainVirtioSerialAddrSetPtr addrs, + virDomainVirtioSerialControllerPtr cont) +{ + size_t i; + + for (i = 0; i < addrs->ncontrollers; i++) { + if (addrs->controllers[i]->idx == cont->idx) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("virtio serial controller with index %u already exists" + " in the address set"), + cont->idx); + return -2; + } + if (addrs->controllers[i]->idx > cont->idx) + return i; + } + return -1; +} + +static ssize_t +virDomainVirtioSerialAddrFindController(virDomainVirtioSerialAddrSetPtr addrs, + unsigned int idx) +{ + size_t i; + + for (i = 0; i < addrs->ncontrollers; i++) { + if (addrs->controllers[i]->idx == idx) + return i; + } + return -1; +} + +/* virDomainVirtioSerialAddrSetAddController + * + * Adds virtio serial ports of the existing controller + * to the address set. + */ +int +virDomainVirtioSerialAddrSetAddController(virDomainVirtioSerialAddrSetPtr addrs, + virDomainControllerDefPtr cont) +{ + int ret = -1; + int ports; + virDomainVirtioSerialControllerPtr cnt = NULL; + ssize_t insertAt; + + if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) + return 0; + + ports = cont->opts.vioserial.ports; + if (ports == -1) + ports = VIR_DOMAIN_DEFAULT_VIRTIO_SERIAL_PORTS; + + VIR_DEBUG("Adding virtio serial controller index %u with %d" + " ports to the address set", cont->idx, ports); + + if (VIR_ALLOC(cnt) < 0) + goto cleanup; + + if (!(cnt->ports = virBitmapNew(ports))) + goto cleanup; + cnt->idx = cont->idx; + + if ((insertAt = virDomainVirtioSerialAddrPlaceController(addrs, cnt)) < -1) + goto cleanup; + if (VIR_INSERT_ELEMENT(addrs->controllers, insertAt, + addrs->ncontrollers, cnt) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virDomainVirtioSerialControllerFree(cnt); + return ret; +} + +/* virDomainVirtioSerialAddrSetAddControllers + * + * Adds virtio serial ports of controllers present in the domain definition + * to the address set. + */ +int +virDomainVirtioSerialAddrSetAddControllers(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDefPtr def) +{ + size_t i; + + for (i = 0; i < def->ncontrollers; i++) { + if (virDomainVirtioSerialAddrSetAddController(addrs, + def->controllers[i]) < 0) + return -1; + } + + return 0; +} + +/* virDomainVirtioSerialAddrSetRemoveController + * + * Removes a virtio serial controller from the address set. + */ +void +virDomainVirtioSerialAddrSetRemoveController(virDomainVirtioSerialAddrSetPtr addrs, + virDomainControllerDefPtr cont) +{ + ssize_t pos; + + if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) + return; + + VIR_DEBUG("Removing virtio serial controller index %u " + "from the address set", cont->idx); + + pos = virDomainVirtioSerialAddrFindController(addrs, cont->idx); + + if (pos >= 0) + VIR_DELETE_ELEMENT(addrs->controllers, pos, addrs->ncontrollers); +} + +void +virDomainVirtioSerialAddrSetFree(virDomainVirtioSerialAddrSetPtr addrs) +{ + size_t i; + if (addrs) { + for (i = 0; i < addrs->ncontrollers; i++) + virDomainVirtioSerialControllerFree(addrs->controllers[i]); + VIR_FREE(addrs); + } +} + +static int +virDomainVirtioSerialAddrNext(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDeviceVirtioSerialAddress *addr, + bool allowZero) +{ + int ret = -1; + ssize_t port, startPort = 0; + ssize_t i; + unsigned int controller; + + /* port number 0 is reserved for virtconsoles */ + if (allowZero) + startPort = -1; + + if (addrs->ncontrollers == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("no virtio-serial controllers are available")); + goto cleanup; + } + + for (i = 0; i < addrs->ncontrollers; i++) { + virBitmapPtr map = addrs->controllers[i]->ports; + if ((port = virBitmapNextClearBit(map, startPort)) >= 0) { + controller = addrs->controllers[i]->idx; + goto success; + } + } + + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Unable to find a free virtio-serial port")); + + cleanup: + return ret; + + success: + addr->bus = 0; + addr->port = port; + addr->controller = controller; + VIR_DEBUG("Found free virtio serial controller %u port %u", addr->controller, + addr->port); + ret = 0; + goto cleanup; +} + +static int +virDomainVirtioSerialAddrNextFromController(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDeviceVirtioSerialAddress *addr) +{ + ssize_t port; + ssize_t i; + virBitmapPtr map; + + i = virDomainVirtioSerialAddrFindController(addrs, addr->controller); + if (i < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("virtio-serial controller %u not available"), + addr->controller); + return -1; + } + + map = addrs->controllers[i]->ports; + if ((port = virBitmapNextClearBit(map, 0)) <= 0) { + virReportError(VIR_ERR_XML_ERROR, + _("Unable to find a free port on virtio-serial controller %u"), + addr->controller); + return -1; + } + + addr->bus = 0; + addr->port = port; + VIR_DEBUG("Found free virtio serial controller %u port %u", addr->controller, + addr->port); + return 0; +} + +/* virDomainVirtioSerialAddrAutoAssign + * + * reserve a virtio serial address of the device (if it has one) + * or assign a virtio serial address to the device + */ +int +virDomainVirtioSerialAddrAutoAssign(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDeviceInfoPtr info, + bool allowZero) +{ + bool portOnly = info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL; + if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL && + info->addr.vioserial.port) + return virDomainVirtioSerialAddrReserve(NULL, NULL, info, addrs); + else + return virDomainVirtioSerialAddrAssign(addrs, info, allowZero, portOnly); +} + + +int +virDomainVirtioSerialAddrAssign(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDeviceInfoPtr info, + bool allowZero, + bool portOnly) +{ + int ret = -1; + virDomainDeviceInfo nfo = { NULL }; + virDomainDeviceInfoPtr ptr = allowZero ? &nfo : info; + + ptr->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL; + + if (portOnly) { + if (virDomainVirtioSerialAddrNextFromController(addrs, + &ptr->addr.vioserial) < 0) + goto cleanup; + } else { + if (virDomainVirtioSerialAddrNext(addrs, &ptr->addr.vioserial, + allowZero) < 0) + goto cleanup; + } + + if (virDomainVirtioSerialAddrReserve(NULL, NULL, ptr, addrs) < 0) + goto cleanup; + + ret = 0; + + cleanup: + return ret; +} + +/* virDomainVirtioSerialAddrIsComplete + * + * Check if the address is complete, or it needs auto-assignment + */ +bool +virDomainVirtioSerialAddrIsComplete(virDomainDeviceInfoPtr info) +{ + return info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL && + info->addr.vioserial.port != 0; +} + +/* virDomainVirtioSerialAddrReserve + * + * Reserve the virtio serial address of the device + * + * For use with virDomainDeviceInfoIterate, + * opaque should be the address set + */ +int +virDomainVirtioSerialAddrReserve(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainDeviceDefPtr dev ATTRIBUTE_UNUSED, + virDomainDeviceInfoPtr info, + void *data) +{ + virDomainVirtioSerialAddrSetPtr addrs = data; + char *str = NULL; + int ret = -1; + virBitmapPtr map = NULL; + bool b; + ssize_t i; + + if (!virDomainVirtioSerialAddrIsComplete(info)) + return 0; + + VIR_DEBUG("Reserving virtio serial %u %u", info->addr.vioserial.controller, + info->addr.vioserial.port); + + i = virDomainVirtioSerialAddrFindController(addrs, info->addr.vioserial.controller); + if (i < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("virtio serial controller %u is missing"), + info->addr.vioserial.controller); + goto cleanup; + } + + map = addrs->controllers[i]->ports; + if (virBitmapGetBit(map, info->addr.vioserial.port, &b) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("virtio serial controller %u does not have port %u"), + info->addr.vioserial.controller, + info->addr.vioserial.port); + goto cleanup; + } + + if (b) { + virReportError(VIR_ERR_XML_ERROR, + _("virtio serial port %u on controller %u is already occupied"), + info->addr.vioserial.port, + info->addr.vioserial.controller); + goto cleanup; + } + + ignore_value(virBitmapSetBit(map, info->addr.vioserial.port)); + + ret = 0; + + cleanup: + VIR_FREE(str); + return ret; +} + +/* virDomainVirtioSerialAddrRelease + * + * Release the virtio serial address of the device + */ +int +virDomainVirtioSerialAddrRelease(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDeviceInfoPtr info) +{ + virBitmapPtr map; + char *str = NULL; + int ret = -1; + ssize_t i; + + if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL || + info->addr.vioserial.port == 0) + return 0; + + VIR_DEBUG("Releasing virtio serial %u %u", info->addr.vioserial.controller, + info->addr.vioserial.port); + + i = virDomainVirtioSerialAddrFindController(addrs, info->addr.vioserial.controller); + if (i < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("virtio serial controller %u is missing"), + info->addr.vioserial.controller); + goto cleanup; + } + + map = addrs->controllers[i]->ports; + if (virBitmapClearBit(map, info->addr.vioserial.port) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("virtio serial controller %u does not have port %u"), + info->addr.vioserial.controller, + info->addr.vioserial.port); + goto cleanup; + } + + ret = 0; + + cleanup: + VIR_FREE(str); + return ret; +} diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index 2c3468e9e1..14ffd17b4d 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -173,4 +173,63 @@ int virDomainCCWAddressReleaseAddr(virDomainCCWAddressSetPtr addrs, virDomainDeviceInfoPtr dev) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); virDomainCCWAddressSetPtr virDomainCCWAddressSetCreate(void); + +struct _virDomainVirtioSerialController { + unsigned int idx; + virBitmapPtr ports; +}; + +typedef struct _virDomainVirtioSerialController virDomainVirtioSerialController; +typedef virDomainVirtioSerialController *virDomainVirtioSerialControllerPtr; + +struct _virDomainVirtioSerialAddrSet { + virDomainVirtioSerialControllerPtr *controllers; + size_t ncontrollers; +}; +typedef struct _virDomainVirtioSerialAddrSet virDomainVirtioSerialAddrSet; +typedef virDomainVirtioSerialAddrSet *virDomainVirtioSerialAddrSetPtr; + +virDomainVirtioSerialAddrSetPtr +virDomainVirtioSerialAddrSetCreate(void); +int +virDomainVirtioSerialAddrSetAddController(virDomainVirtioSerialAddrSetPtr addrs, + virDomainControllerDefPtr cont) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +void +virDomainVirtioSerialAddrSetRemoveController(virDomainVirtioSerialAddrSetPtr addrs, + virDomainControllerDefPtr cont) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +int +virDomainVirtioSerialAddrSetAddControllers(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDefPtr def) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +void +virDomainVirtioSerialAddrSetFree(virDomainVirtioSerialAddrSetPtr addrs); +bool +virDomainVirtioSerialAddrIsComplete(virDomainDeviceInfoPtr info); +int +virDomainVirtioSerialAddrAutoAssign(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDeviceInfoPtr info, + bool allowZero) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +int +virDomainVirtioSerialAddrAssign(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDeviceInfoPtr info, + bool allowZero, + bool portOnly) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +int +virDomainVirtioSerialAddrReserve(virDomainDefPtr def, + virDomainDeviceDefPtr dev, + virDomainDeviceInfoPtr info, + void *data) + ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4); + +int +virDomainVirtioSerialAddrRelease(virDomainVirtioSerialAddrSetPtr addrs, + virDomainDeviceInfoPtr info) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + #endif /* __DOMAIN_ADDR_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 9e71b1a8c4..5201416c4e 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -108,6 +108,16 @@ virDomainPCIAddressSetFree; virDomainPCIAddressSetGrow; virDomainPCIAddressSlotInUse; virDomainPCIAddressValidate; +virDomainVirtioSerialAddrAssign; +virDomainVirtioSerialAddrAutoAssign; +virDomainVirtioSerialAddrIsComplete; +virDomainVirtioSerialAddrRelease; +virDomainVirtioSerialAddrReserve; +virDomainVirtioSerialAddrSetAddController; +virDomainVirtioSerialAddrSetAddControllers; +virDomainVirtioSerialAddrSetCreate; +virDomainVirtioSerialAddrSetFree; +virDomainVirtioSerialAddrSetRemoveController; # conf/domain_audit.h