static int xenFormatXLDisk(virConfValuePtr list, virDomainDiskDefPtr disk) { virBuffer buf = VIR_BUFFER_INITIALIZER; virConfValuePtr val, tmp; const char *src = virDomainDiskGetSource(disk); int format = virDomainDiskGetFormat(disk); const char *driver = virDomainDiskGetDriver(disk); /* target */ virBufferAsprintf(&buf, "%s,", src); /* format */ switch (format) { case VIR_STORAGE_FILE_RAW: virBufferAddLit(&buf, "raw,"); break; case VIR_STORAGE_FILE_VHD: virBufferAddLit(&buf, "xvhd,"); break; case VIR_STORAGE_FILE_QCOW: virBufferAddLit(&buf, "qcow,"); break; case VIR_STORAGE_FILE_QCOW2: virBufferAddLit(&buf, "qcow2,"); break; /* set default */ default: virBufferAddLit(&buf, "raw,"); } /* device */ virBufferAdd(&buf, disk->dst, -1); virBufferAddLit(&buf, ","); if (disk->src->readonly) virBufferAddLit(&buf, "r,"); else if (disk->src->shared) virBufferAddLit(&buf, "!,"); else virBufferAddLit(&buf, "w,"); if (disk->transient) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("transient disks not supported yet")); goto cleanup; } if (STREQ_NULLABLE(driver, "qemu")) virBufferAddLit(&buf, "backendtype=qdisk"); else if (STREQ_NULLABLE(driver, "tap")) virBufferAddLit(&buf, "backendtype=tap"); else if (STREQ_NULLABLE(driver, "phy")) virBufferAddLit(&buf, "backendtype=phy"); if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) virBufferAddLit(&buf, ",devtype=cdrom"); if (virBufferCheckError(&buf) < 0) goto cleanup; if (VIR_ALLOC(val) < 0) goto cleanup; val->type = VIR_CONF_STRING; val->str = virBufferContentAndReset(&buf); tmp = list->list; while (tmp && tmp->next) tmp = tmp->next; if (tmp) tmp->next = val; else list->list = val; return 0; cleanup: virBufferFreeAndReset(&buf); return -1; }
static int testQemuMonitorJSONGetCommands(const void *data) { virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; qemuMonitorTestPtr test = qemuMonitorTestNew(true, xmlopt); int ret = -1; char **commands = NULL; int ncommands = 0; int i; if (!test) return -1; if (qemuMonitorTestAddItem(test, "query-commands", "{ " " \"return\": [ " " { " " \"name\": \"system_wakeup\" " " }, " " { " " \"name\": \"cont\" " " }, " " { " " \"name\": \"quit\" " " } " " ]" "}") < 0) goto cleanup; if ((ncommands = qemuMonitorGetCommands(qemuMonitorTestGetMonitor(test), &commands)) < 0) goto cleanup; if (ncommands != 3) { virReportError(VIR_ERR_INTERNAL_ERROR, "ncommands %d is not 3", ncommands); goto cleanup; } #define CHECK(i, wantname) \ do { \ if (STRNEQ(commands[i], (wantname))) { \ virReportError(VIR_ERR_INTERNAL_ERROR, \ "name %s is not %s", \ commands[i], (wantname)); \ goto cleanup; \ } \ } while (0) CHECK(0, "system_wakeup"); CHECK(1, "cont"); CHECK(2, "quit"); #undef CHECK ret = 0; cleanup: qemuMonitorTestFree(test); for (i = 0; i < ncommands; i++) VIR_FREE(commands[i]); VIR_FREE(commands); return ret; }
int openvzReadNetworkConf(virDomainDefPtr def, int veid) { int ret; virDomainNetDefPtr net = NULL; char *temp = NULL; char *token, *saveptr = NULL; /*parse routing network configuration* * Sample from config: * IP_ADDRESS="1.1.1.1 1.1.1.2" * splited IPs by space */ ret = openvzReadVPSConfigParam(veid, "IP_ADDRESS", &temp); if (ret < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not read 'IP_ADDRESS' from config for container %d"), veid); goto error; } else if (ret > 0) { token = strtok_r(temp, " ", &saveptr); while (token != NULL) { if (VIR_ALLOC(net) < 0) goto no_memory; net->type = VIR_DOMAIN_NET_TYPE_ETHERNET; net->data.ethernet.ipaddr = strdup(token); if (net->data.ethernet.ipaddr == NULL) goto no_memory; if (VIR_REALLOC_N(def->nets, def->nnets + 1) < 0) goto no_memory; def->nets[def->nnets++] = net; net = NULL; token = strtok_r(NULL, " ", &saveptr); } } /*parse bridge devices*/ /*Sample from config: *NETIF="ifname=eth10,mac=00:18:51:C1:05:EE,host_ifname=veth105.10,host_mac=00:18:51:8F:D9:F3" *devices splited by ';' */ ret = openvzReadVPSConfigParam(veid, "NETIF", &temp); if (ret < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not read 'NETIF' from config for container %d"), veid); goto error; } else if (ret > 0) { token = strtok_r(temp, ";", &saveptr); while (token != NULL) { /*add new device to list*/ if (VIR_ALLOC(net) < 0) goto no_memory; net->type = VIR_DOMAIN_NET_TYPE_BRIDGE; char *p = token; char cpy_temp[32]; int len; /*parse string*/ do { char *next = strchrnul(p, ','); if (STRPREFIX(p, "ifname=")) { /* skip in libvirt */ } else if (STRPREFIX(p, "host_ifname=")) { p += 12; len = next - p; if (len > 16) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Too long network device name")); goto error; } if (VIR_ALLOC_N(net->ifname, len+1) < 0) goto no_memory; if (virStrncpy(net->ifname, p, len, len+1) == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Network ifname %s too long for destination"), p); goto error; } } else if (STRPREFIX(p, "bridge=")) { p += 7; len = next - p; if (len > 16) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Too long bridge device name")); goto error; } if (VIR_ALLOC_N(net->data.bridge.brname, len+1) < 0) goto no_memory; if (virStrncpy(net->data.bridge.brname, p, len, len+1) == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Bridge name %s too long for destination"), p); goto error; } } else if (STRPREFIX(p, "mac=")) { p += 4; len = next - p; if (len != 17) { /* should be 17 */ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Wrong length MAC address")); goto error; } if (virStrncpy(cpy_temp, p, len, sizeof(cpy_temp)) == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("MAC address %s too long for destination"), p); goto error; } if (virMacAddrParse(cpy_temp, &net->mac) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Wrong MAC address")); goto error; } } p = ++next; } while (p < token + strlen(token)); if (VIR_REALLOC_N(def->nets, def->nnets + 1) < 0) goto no_memory; def->nets[def->nnets++] = net; net = NULL; token = strtok_r(NULL, ";", &saveptr); } } VIR_FREE(temp); return 0; no_memory: virReportOOMError(); error: VIR_FREE(temp); virDomainNetDefFree(net); return -1; }
/* * Parse the /usr/sbin/bhyveload command line. */ static int bhyveParseBhyveLoadCommandLine(virDomainDefPtr def, int argc, char **argv) { int c; /* bhyveload called with default arguments when only -m and -d are given. * Store this in a bit field and check if only those two options are given * later */ unsigned arguments = 0; size_t memory = 0; struct _getopt_data *parser; size_t i = 0; int ret = -1; const char optstr[] = "CSc:d:e:h:l:m:"; if (!argv) goto error; if (VIR_ALLOC(parser) < 0) goto error; while ((c = _getopt_internal_r(argc, argv, optstr, NULL, NULL, 0, parser, 0)) != -1) { switch (c) { case 'd': arguments |= 1; /* Iterate over the disks of the domain trying to match up the * source */ for (i = 0; i < def->ndisks; i++) { if (STREQ(virDomainDiskGetSource(def->disks[i]), parser->optarg)) { def->disks[i]->info.bootIndex = i; break; } } break; case 'm': arguments |= 2; if (bhyveParseMemsize(parser->optarg, &memory)) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Failed to parse memory")); goto error; } if (def->mem.cur_balloon != 0 && def->mem.cur_balloon != memory) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Failed to parse memory: size mismatch")); goto error; } def->mem.cur_balloon = memory; virDomainDefSetMemoryTotal(def, memory); break; default: arguments |= 4; } } if (arguments != 3) { /* Set os.bootloader since virDomainDefFormatInternal will only format * the bootloader arguments if os->bootloader is set. */ if (VIR_STRDUP(def->os.bootloader, argv[0]) < 0) goto error; def->os.bootloaderArgs = virStringJoin((const char**) &argv[1], " "); } if (argc != parser->optind) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Failed to parse arguments for bhyveload command")); goto error; } if (def->name == NULL) { if (VIR_STRDUP(def->name, argv[argc]) < 0) goto error; } else if (STRNEQ(def->name, argv[argc])) { /* the vm name of the loader and the bhyverun command differ, throw an * error here */ virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Failed to parse arguments: VM name mismatch")); goto error; } ret = 0; error: VIR_FREE(parser); return ret; }
static int testQemuMonitorJSONGetMachines(const void *data) { virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; qemuMonitorTestPtr test = qemuMonitorTestNew(true, xmlopt); int ret = -1; qemuMonitorMachineInfoPtr *info; int ninfo = 0; const char *null = NULL; int i; if (!test) return -1; if (qemuMonitorTestAddItem(test, "query-machines", "{ " " \"return\": [ " " { " " \"name\": \"pc-1.0\" " " }, " " { " " \"name\": \"pc-1.1\" " " }, " " { " " \"name\": \"pc-1.2\", " " \"is-default\": true, " " \"alias\": \"pc\" " " } " " ]" "}") < 0) goto cleanup; if ((ninfo = qemuMonitorGetMachines(qemuMonitorTestGetMonitor(test), &info)) < 0) goto cleanup; if (ninfo != 3) { virReportError(VIR_ERR_INTERNAL_ERROR, "ninfo %d is not 3", ninfo); goto cleanup; } #define CHECK(i, wantname, wantisDefault, wantalias) \ do { \ if (STRNEQ(info[i]->name, (wantname))) { \ virReportError(VIR_ERR_INTERNAL_ERROR, \ "name %s is not %s", \ info[i]->name, (wantname)); \ goto cleanup; \ } \ if (info[i]->isDefault != (wantisDefault)) { \ virReportError(VIR_ERR_INTERNAL_ERROR, \ "isDefault %d is not %d", \ info[i]->isDefault, (wantisDefault)); \ goto cleanup; \ } \ if (STRNEQ_NULLABLE(info[i]->alias, (wantalias))) { \ virReportError(VIR_ERR_INTERNAL_ERROR, \ "alias %s is not %s", \ info[i]->alias, NULLSTR(wantalias)); \ goto cleanup; \ } \ } while (0) CHECK(0, "pc-1.0", false, null); CHECK(1, "pc-1.1", false, null); CHECK(2, "pc-1.2", true, "pc"); #undef CHECK ret = 0; cleanup: qemuMonitorTestFree(test); for (i = 0; i < ninfo; i++) qemuMonitorMachineInfoFree(info[i]); VIR_FREE(info); return ret; }
static int bhyveParseBhyveLPCArg(virDomainDefPtr def, unsigned caps ATTRIBUTE_UNUSED, const char *arg) { /* -l emulation[,config] */ const char *separator = NULL; const char *param = NULL; size_t last = 0; virDomainChrDefPtr chr = NULL; char *type = NULL; separator = strchr(arg, ','); param = separator + 1; if (!separator) goto error; if (VIR_STRNDUP(type, arg, separator - arg) < 0) goto error; /* Only support com%d */ if (STRPREFIX(type, "com") && type[4] == 0) { if (!(chr = virDomainChrDefNew(NULL))) goto error; chr->source->type = VIR_DOMAIN_CHR_TYPE_NMDM; chr->source->data.nmdm.master = NULL; chr->source->data.nmdm.slave = NULL; chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; if (!STRPREFIX(param, "/dev/nmdm")) { virReportError(VIR_ERR_OPERATION_FAILED, _("Failed to set com port %s: does not start with " "'/dev/nmdm'."), type); goto error; } if (VIR_STRDUP(chr->source->data.nmdm.master, param) < 0) { virDomainChrDefFree(chr); goto error; } if (VIR_STRDUP(chr->source->data.nmdm.slave, chr->source->data.file.path) < 0) { virDomainChrDefFree(chr); goto error; } /* If the last character of the master is 'A', the slave will be 'B' * and vice versa */ last = strlen(chr->source->data.nmdm.master) - 1; switch (chr->source->data.file.path[last]) { case 'A': chr->source->data.nmdm.slave[last] = 'B'; break; case 'B': chr->source->data.nmdm.slave[last] = 'A'; break; default: virReportError(VIR_ERR_OPERATION_FAILED, _("Failed to set slave for %s: last letter not " "'A' or 'B'"), NULLSTR(chr->source->data.nmdm.master)); goto error; } switch (type[3]-'0') { case 1: case 2: chr->target.port = type[3] - '1'; break; default: virReportError(VIR_ERR_OPERATION_FAILED, _("Failed to parse %s: only com1 and com2" " supported."), type); goto error; break; } if (VIR_APPEND_ELEMENT(def->serials, def->nserials, chr) < 0) { virDomainChrDefFree(chr); goto error; } } VIR_FREE(type); return 0; error: virDomainChrDefFree(chr); VIR_FREE(type); return -1; }
static int bhyveParsePCINet(virDomainDefPtr def, virDomainXMLOptionPtr xmlopt, unsigned caps ATTRIBUTE_UNUSED, unsigned pcislot, unsigned pcibus, unsigned function, const char *config) { /* -s slot,virtio-net,tapN[,mac=xx:xx:xx:xx:xx:xx] */ virDomainNetDefPtr net = NULL; const char *separator = NULL; const char *mac = NULL; if (VIR_ALLOC(net) < 0) goto cleanup; /* Let's just assume it is VIR_DOMAIN_NET_TYPE_ETHERNET, it could also be * a bridge, but this is the most generic option. */ net->type = VIR_DOMAIN_NET_TYPE_ETHERNET; net->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; net->info.addr.pci.slot = pcislot; net->info.addr.pci.bus = pcibus; net->info.addr.pci.function = function; if (!config) goto error; if (!STRPREFIX(config, "tap")) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Only tap devices supported")); goto error; } separator = strchr(config, ','); if (VIR_STRNDUP(net->ifname, config, separator? separator - config : -1) < 0) goto error; if (!separator) goto cleanup; if (!STRPREFIX(++separator, "mac=")) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Only mac option can be specified for virt-net")); goto error; } mac = separator + 4; if (virMacAddrParse(mac, &net->mac) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("unable to parse mac address '%s'"), mac); goto cleanup; } cleanup: if (!mac) virDomainNetGenerateMAC(xmlopt, &net->mac); if (VIR_APPEND_ELEMENT(def->nets, def->nnets, net) < 0) goto error; return 0; error: virDomainNetDefFree(net); return -1; }
/* virNetDevVPortProfileMerge() - merge the attributes in mods into * orig. If anything that is set in mods has already been set in orig * *and doesn't match*, log an error and return -1, otherwise return 0. */ static int virNetDevVPortProfileMerge(virNetDevVPortProfilePtr orig, virNetDevVPortProfilePtr mods) { enum virNetDevVPortProfile otype; if (!orig || !mods) return 0; otype = orig->virtPortType; if (mods->virtPortType != VIR_NETDEV_VPORT_PROFILE_NONE) { if (otype != VIR_NETDEV_VPORT_PROFILE_NONE && otype != mods->virtPortType) { virReportError(VIR_ERR_XML_ERROR, _("attempt to merge virtualports " "with mismatched types (%s and %s)"), virNetDevVPortTypeToString(otype), virNetDevVPortTypeToString(mods->virtPortType)); return -1; } otype = orig->virtPortType = mods->virtPortType; } if (mods->managerID_specified && (otype == VIR_NETDEV_VPORT_PROFILE_8021QBG || otype == VIR_NETDEV_VPORT_PROFILE_NONE)) { if (orig->managerID_specified && (orig->managerID != mods->managerID)) { virReportError(VIR_ERR_XML_ERROR, _("attempt to merge virtualports " "with mismatched managerids (%d and %d)"), orig->managerID, mods->managerID); return -1; } orig->managerID = mods->managerID; orig->managerID_specified = true; } if (mods->typeID_specified && (otype == VIR_NETDEV_VPORT_PROFILE_8021QBG || otype == VIR_NETDEV_VPORT_PROFILE_NONE)) { if (orig->typeID_specified && (orig->typeID != mods->typeID)) { virReportError(VIR_ERR_XML_ERROR, _("attempt to merge virtualports " "with mismatched typeids (%d and %d)"), orig->typeID, mods->typeID); return -1; } orig->typeID = mods->typeID; orig->typeID_specified = true; } if (mods->typeIDVersion_specified && (otype == VIR_NETDEV_VPORT_PROFILE_8021QBG || otype == VIR_NETDEV_VPORT_PROFILE_NONE)) { if (orig->typeIDVersion_specified && (orig->typeIDVersion != mods->typeIDVersion)) { virReportError(VIR_ERR_XML_ERROR, _("attempt to merge virtualports with " "mismatched typeidversions (%d and %d)"), orig->typeIDVersion, mods->typeIDVersion); return -1; } orig->typeIDVersion = mods->typeIDVersion; orig->typeIDVersion_specified = true; } if (mods->instanceID_specified && (otype == VIR_NETDEV_VPORT_PROFILE_8021QBG || otype == VIR_NETDEV_VPORT_PROFILE_NONE)) { if (orig->instanceID_specified && memcmp(orig->instanceID, mods->instanceID, sizeof(orig->instanceID))) { char origuuid[VIR_UUID_STRING_BUFLEN]; char modsuuid[VIR_UUID_STRING_BUFLEN]; virReportError(VIR_ERR_XML_ERROR, _("attempt to merge virtualports with " "mismatched instanceids ('%s' and '%s')"), virUUIDFormat(orig->instanceID, origuuid), virUUIDFormat(mods->instanceID, modsuuid)); return -1; } memcpy(orig->instanceID, mods->instanceID, sizeof(orig->instanceID)); orig->instanceID_specified = true; } if (mods->interfaceID_specified && (otype == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH || otype == VIR_NETDEV_VPORT_PROFILE_NONE)) { if (orig->interfaceID_specified && memcmp(orig->interfaceID, mods->interfaceID, sizeof(orig->interfaceID))) { char origuuid[VIR_UUID_STRING_BUFLEN]; char modsuuid[VIR_UUID_STRING_BUFLEN]; virReportError(VIR_ERR_XML_ERROR, _("attempt to merge virtualports with " "mismatched interfaceids ('%s' and '%s')"), virUUIDFormat(orig->interfaceID, origuuid), virUUIDFormat(mods->interfaceID, modsuuid)); return -1; } memcpy(orig->interfaceID, mods->interfaceID, sizeof(orig->interfaceID)); orig->interfaceID_specified = true; } if (mods->profileID[0] && (otype == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH || otype == VIR_NETDEV_VPORT_PROFILE_8021QBH || otype == VIR_NETDEV_VPORT_PROFILE_NONE)) { if (orig->profileID[0] && STRNEQ(orig->profileID, mods->profileID)) { virReportError(VIR_ERR_XML_ERROR, _("attempt to merge virtualports with " "mismatched profileids ('%s' and '%s')"), orig->profileID, mods->profileID); return -1; } if (virStrcpyStatic(orig->profileID, mods->profileID) == NULL) { /* this should never happen - it indicates mods->profileID * isn't properly null terminated. */ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("corrupted profileid string")); return -1; } } return 0; }
/** * virNetDevVPortProfileGetStatus: * * tb: top level netlink response attributes + values * vf: The virtual function used in the request * instanceId: instanceId of the interface (vm uuid in case of 802.1Qbh) * is8021Qbg: whether this function is call for 8021Qbg * status: pointer to a uint16 where the status will be written into * * Get the status from the IFLA_PORT_RESPONSE field; Returns 0 in * case of success, < 0 otherwise with error having been reported */ static int virNetDevVPortProfileGetStatus(struct nlattr **tb, int32_t vf, const unsigned char *instanceId, bool nltarget_kernel, bool is8021Qbg, uint16_t *status) { int rc = -1; struct nlattr *tb_port[IFLA_PORT_MAX + 1] = { NULL, }; if (vf == PORT_SELF_VF && nltarget_kernel) { if (tb[IFLA_PORT_SELF]) { if (nla_parse_nested(tb_port, IFLA_PORT_MAX, tb[IFLA_PORT_SELF], ifla_port_policy)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("error parsing IFLA_PORT_SELF part")); goto cleanup; } } else { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("IFLA_PORT_SELF is missing")); goto cleanup; } } else { if (tb[IFLA_VF_PORTS]) { int rem; bool found = false; struct nlattr *tb_vf_ports = { NULL, }; nla_for_each_nested(tb_vf_ports, tb[IFLA_VF_PORTS], rem) { if (nla_type(tb_vf_ports) != IFLA_VF_PORT) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("error while iterating over " "IFLA_VF_PORTS part")); goto cleanup; } if (nla_parse_nested(tb_port, IFLA_PORT_MAX, tb_vf_ports, ifla_port_policy)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("error parsing IFLA_VF_PORT part")); goto cleanup; } /* This ensures that the given VF is present in the * IFLA_VF_PORTS list, and that its uuid matches the * instanceId (in case we've associated it). If no * instanceId is sent from the caller, that means we've * disassociated it from this instanceId, and the uuid * will either be unset (if still not associated with * anything) or will be set to a new and different uuid */ if ((tb_port[IFLA_PORT_VF] && vf == *(uint32_t *)RTA_DATA(tb_port[IFLA_PORT_VF])) && (!instanceId || (tb_port[IFLA_PORT_INSTANCE_UUID] && !memcmp(instanceId, (unsigned char *) RTA_DATA(tb_port[IFLA_PORT_INSTANCE_UUID]), VIR_UUID_BUFLEN)))) { found = true; break; } } if (!found) { char instanceIdStr[VIR_UUID_STRING_BUFLEN] = "(none)"; if (instanceId) virUUIDFormat(instanceId, instanceIdStr); virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not find vf/instanceId %u/%s " " in netlink response"), vf, instanceIdStr); /* go through all the entries again. This seems tedious, * but experience has shown the resulting log to be * very useful. */ VIR_WARN("IFLA_VF_PORTS entries that were returned:"); nla_for_each_nested(tb_vf_ports, tb[IFLA_VF_PORTS], rem) { char uuidstr[VIR_UUID_STRING_BUFLEN] = "(none)"; if (nla_parse_nested(tb_port, IFLA_PORT_MAX, tb_vf_ports, ifla_port_policy)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("error parsing IFLA_VF_PORT " "during error reporting")); goto cleanup; } if (tb_port[IFLA_PORT_INSTANCE_UUID]) { virUUIDFormat((unsigned char *) RTA_DATA(tb_port[IFLA_PORT_INSTANCE_UUID]), uuidstr); } VIR_WARN(" vf: %d uuid: %s", tb_port[IFLA_PORT_VF] ? *(uint32_t *)RTA_DATA(tb_port[IFLA_PORT_VF]) : -1, uuidstr); } goto cleanup; } } else {
int openvzLoadDomains(struct openvz_driver *driver) { int veid, ret; char *status; char uuidstr[VIR_UUID_STRING_BUFLEN]; virDomainObjPtr dom = NULL; virDomainDefPtr def = NULL; char *temp = NULL; char *outbuf = NULL; char *line; virCommandPtr cmd = NULL; if (openvzAssignUUIDs() < 0) return -1; cmd = virCommandNewArgList(VZLIST, "-a", "-ovpsid,status", "-H", NULL); virCommandSetOutputBuffer(cmd, &outbuf); if (virCommandRun(cmd, NULL) < 0) goto cleanup; line = outbuf; while (line[0] != '\0') { unsigned int flags = 0; if (virStrToLong_i(line, &status, 10, &veid) < 0 || *status++ != ' ' || (line = strchr(status, '\n')) == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Failed to parse vzlist output")); goto cleanup; } *line++ = '\0'; if (VIR_ALLOC(def) < 0) goto cleanup; def->virtType = VIR_DOMAIN_VIRT_OPENVZ; if (STREQ(status, "stopped")) def->id = -1; else def->id = veid; if (virAsprintf(&def->name, "%i", veid) < 0) goto cleanup; openvzGetVPSUUID(veid, uuidstr, sizeof(uuidstr)); ret = virUUIDParse(uuidstr, def->uuid); if (ret == -1) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("UUID in config file malformed")); goto cleanup; } if (VIR_STRDUP(def->os.type, "exe") < 0) goto cleanup; if (VIR_STRDUP(def->os.init, "/sbin/init") < 0) goto cleanup; ret = openvzReadVPSConfigParam(veid, "CPUS", &temp); if (ret < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not read config for container %d"), veid); goto cleanup; } else if (ret > 0) { def->maxvcpus = strtoI(temp); } if (ret == 0 || def->maxvcpus == 0) def->maxvcpus = openvzGetNodeCPUs(); def->vcpus = def->maxvcpus; /* XXX load rest of VM config data .... */ openvzReadNetworkConf(def, veid); openvzReadFSConf(def, veid); openvzReadMemConf(def, veid); virUUIDFormat(def->uuid, uuidstr); flags = VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE; if (STRNEQ(status, "stopped")) flags |= VIR_DOMAIN_OBJ_LIST_ADD_LIVE; if (!(dom = virDomainObjListAdd(driver->domains, def, driver->xmlopt, flags, NULL))) goto cleanup; if (STREQ(status, "stopped")) { virDomainObjSetState(dom, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_UNKNOWN); dom->pid = -1; } else { virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNKNOWN); dom->pid = veid; } /* XXX OpenVZ doesn't appear to have concept of a transient domain */ dom->persistent = 1; virObjectUnlock(dom); dom = NULL; def = NULL; } virCommandFree(cmd); VIR_FREE(temp); VIR_FREE(outbuf); return 0; cleanup: virCommandFree(cmd); VIR_FREE(temp); VIR_FREE(outbuf); virObjectUnref(dom); virDomainDefFree(def); return -1; }
/* virNetDevVPortProfileCheckComplete() checks that all attributes * required for the type of virtport are specified. When * generateMissing is true, any missing attribute that can be * autogenerated, will be (instanceid, interfaceid). If virtport == * NULL or virtPortType == NONE, then the result is always 0 * (success). If a required attribute is missing, an error is logged * and -1 is returned. */ int virNetDevVPortProfileCheckComplete(virNetDevVPortProfilePtr virtport, bool generateMissing) { const char *missing = NULL; if (!virtport || virtport->virtPortType == VIR_NETDEV_VPORT_PROFILE_NONE) return 0; switch (virtport->virtPortType) { case VIR_NETDEV_VPORT_PROFILE_8021QBG: if (!virtport->managerID_specified) { missing = "managerid"; } else if (!virtport->typeID_specified) { missing = "typeid"; } else if (!virtport->typeIDVersion_specified) { missing = "typeidversion"; } else if (!virtport->instanceID_specified) { if (generateMissing) { if (virUUIDGenerate(virtport->instanceID) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot generate a random uuid for instanceid")); return -1; } virtport->instanceID_specified = true; } else { missing = "instanceid"; } } break; case VIR_NETDEV_VPORT_PROFILE_8021QBH: if (!virtport->profileID[0]) missing = "profileid"; break; case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH: /* profileid is optional for openvswitch */ if (!virtport->interfaceID_specified) { if (generateMissing) { if (virUUIDGenerate(virtport->interfaceID) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot generate a random uuid for interfaceid")); return -1; } virtport->interfaceID_specified = true; } else { missing = "interfaceid"; } } break; case VIR_NETDEV_VPORT_PROFILE_MIDONET: if (!virtport->interfaceID_specified) missing = "interfaceid"; break; } if (missing) { virReportError(VIR_ERR_XML_ERROR, _("missing %s in <virtualport type='%s'>"), missing, virNetDevVPortTypeToString(virtport->virtPortType)); return -1; } return 0; }
static int openvzReadMemConf(virDomainDefPtr def, int veid) { int ret = -1; char *temp = NULL; unsigned long long barrier, limit; const char *param; long kb_per_pages; kb_per_pages = openvzKBPerPages(); if (kb_per_pages < 0) goto error; /* Memory allocation guarantee */ param = "VMGUARPAGES"; ret = openvzReadVPSConfigParam(veid, param, &temp); if (ret < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not read '%s' from config for container %d"), param, veid); goto error; } else if (ret > 0) { ret = openvzParseBarrierLimit(temp, &barrier, NULL); if (ret < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not parse barrier of '%s' " "from config for container %d"), param, veid); goto error; } if (barrier == LONG_MAX) def->mem.min_guarantee = 0ull; else def->mem.min_guarantee = barrier * kb_per_pages; } /* Memory hard and soft limits */ param = "PRIVVMPAGES"; ret = openvzReadVPSConfigParam(veid, param, &temp); if (ret < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not read '%s' from config for container %d"), param, veid); goto error; } else if (ret > 0) { ret = openvzParseBarrierLimit(temp, &barrier, &limit); if (ret < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not parse barrier and limit of '%s' " "from config for container %d"), param, veid); goto error; } if (barrier == LONG_MAX) def->mem.soft_limit = 0ull; else def->mem.soft_limit = barrier * kb_per_pages; if (limit == LONG_MAX) def->mem.hard_limit = 0ull; else def->mem.hard_limit = limit * kb_per_pages; } ret = 0; error: VIR_FREE(temp); return ret; }
/* * Attempt to create a new LUN * * Returns: * * 0 => Success * -1 => Failure due to some sort of OOM or other fatal issue found when * attempting to get/update information about a found volume * -2 => Failure to find a stable path, not fatal, caller can try another */ static int virStorageBackendSCSINewLun(virStoragePoolObjPtr pool, uint32_t host ATTRIBUTE_UNUSED, uint32_t bus, uint32_t target, uint32_t lun, const char *dev) { virStorageVolDefPtr vol = NULL; char *devpath = NULL; int retval = -1; /* Check if the pool is using a stable target path. The call to * virStorageBackendStablePath will fail if the pool target path * isn't stable and just return the strdup'd 'devpath' anyway. * This would be indistinguishable to failing to find the stable * path to the device if the virDirRead loop to search the * target pool path for our devpath had failed. */ if (!virStorageBackendPoolPathIsStable(pool->def->target.path) && !(STREQ(pool->def->target.path, "/dev") || STREQ(pool->def->target.path, "/dev/"))) { virReportError(VIR_ERR_INVALID_ARG, _("unable to use target path '%s' for dev '%s'"), NULLSTR(pool->def->target.path), dev); goto cleanup; } if (VIR_ALLOC(vol) < 0) goto cleanup; vol->type = VIR_STORAGE_VOL_BLOCK; /* 'host' is dynamically allocated by the kernel, first come, * first served, per HBA. As such it isn't suitable for use * in the volume name. We only need uniqueness per-pool, so * just leave 'host' out */ if (virAsprintf(&(vol->name), "unit:%u:%u:%u", bus, target, lun) < 0) goto cleanup; if (virAsprintf(&devpath, "/dev/%s", dev) < 0) goto cleanup; VIR_DEBUG("Trying to create volume for '%s'", devpath); /* Now figure out the stable path * * XXX this method is O(N) because it scans the pool target * dir every time its run. Should figure out a more efficient * way of doing this... */ if ((vol->target.path = virStorageBackendStablePath(pool, devpath, true)) == NULL) goto cleanup; if (STREQ(devpath, vol->target.path) && !(STREQ(pool->def->target.path, "/dev") || STREQ(pool->def->target.path, "/dev/"))) { VIR_DEBUG("No stable path found for '%s' in '%s'", devpath, pool->def->target.path); retval = -2; goto cleanup; } /* Allow a volume read failure to ignore or skip this block file */ if ((retval = virStorageBackendUpdateVolInfo(vol, true, VIR_STORAGE_VOL_OPEN_DEFAULT, VIR_STORAGE_VOL_READ_NOERROR)) < 0) goto cleanup; if (!(vol->key = virStorageBackendSCSISerial(vol->target.path))) goto cleanup; pool->def->capacity += vol->target.capacity; pool->def->allocation += vol->target.allocation; if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0) goto cleanup; vol = NULL; retval = 0; cleanup: virStorageVolDefFree(vol); VIR_FREE(devpath); return retval; }
static int testSELinuxLoadFileList(const char *testname, testSELinuxFile **files, size_t *nfiles) { int ret = -1; char *path = NULL; FILE *fp = NULL; char *line = NULL; *files = NULL; *nfiles = 0; if (virAsprintf(&path, "%s/securityselinuxlabeldata/%s.txt", abs_srcdir, testname) < 0) goto cleanup; if (!(fp = fopen(path, "r"))) goto cleanup; if (VIR_ALLOC_N(line, 1024) < 0) goto cleanup; while (!feof(fp)) { char *file = NULL, *context = NULL, *tmp; if (!fgets(line, 1024, fp)) { if (!feof(fp)) goto cleanup; break; } tmp = strchr(line, ';'); if (!tmp) { virReportError(VIR_ERR_INTERNAL_ERROR, "unexpected format for line '%s'", line); goto cleanup; } *tmp = '\0'; tmp++; if (virAsprintf(&file, "%s/securityselinuxlabeldata%s", abs_builddir, line) < 0) goto cleanup; if (*tmp != '\0' && *tmp != '\n') { if (VIR_STRDUP(context, tmp) < 0) { VIR_FREE(file); goto cleanup; } tmp = strchr(context, '\n'); if (tmp) *tmp = '\0'; } if (VIR_EXPAND_N(*files, *nfiles, 1) < 0) { VIR_FREE(file); VIR_FREE(context); goto cleanup; } (*files)[(*nfiles)-1].file = file; (*files)[(*nfiles)-1].context = context; } ret = 0; cleanup: VIR_FORCE_FCLOSE(fp); VIR_FREE(path); VIR_FREE(line); return ret; }
/* Masquerade all traffic coming from the network associated * with the bridge */ static int iptablesForwardMasquerade(virSocketAddr *netaddr, unsigned int prefix, const char *physdev, virSocketAddrRangePtr addr, virPortRangePtr port, const char *protocol, int action) { int ret = -1; char *networkstr = NULL; char *addrStartStr = NULL; char *addrEndStr = NULL; char *portRangeStr = NULL; char *natRangeStr = NULL; virCommandPtr cmd = NULL; if (!(networkstr = iptablesFormatNetwork(netaddr, prefix))) return -1; if (!VIR_SOCKET_ADDR_IS_FAMILY(netaddr, AF_INET)) { /* Higher level code *should* guaranteee it's impossible to get here. */ virReportError(VIR_ERR_INTERNAL_ERROR, _("Attempted to NAT '%s'. NAT is only supported for IPv4."), networkstr); goto cleanup; } if (VIR_SOCKET_ADDR_IS_FAMILY(&addr->start, AF_INET)) { if (!(addrStartStr = virSocketAddrFormat(&addr->start))) goto cleanup; if (VIR_SOCKET_ADDR_IS_FAMILY(&addr->end, AF_INET)) { if (!(addrEndStr = virSocketAddrFormat(&addr->end))) goto cleanup; } } cmd = iptablesCommandNew("nat", "POSTROUTING", AF_INET, action); virCommandAddArgList(cmd, "--source", networkstr, NULL); if (protocol && protocol[0]) virCommandAddArgList(cmd, "-p", protocol, NULL); virCommandAddArgList(cmd, "!", "--destination", networkstr, NULL); if (physdev && physdev[0]) virCommandAddArgList(cmd, "--out-interface", physdev, NULL); if (protocol && protocol[0]) { if (port->start == 0 && port->end == 0) { port->start = 1024; port->end = 65535; } if (port->start < port->end && port->end < 65536) { if (virAsprintf(&portRangeStr, ":%u-%u", port->start, port->end) < 0) goto cleanup; } else { virReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid port range '%u-%u'."), port->start, port->end); } } /* Use --jump SNAT if public addr is specified */ if (addrStartStr && addrStartStr[0]) { int r = 0; if (addrEndStr && addrEndStr[0]) { r = virAsprintf(&natRangeStr, "%s-%s%s", addrStartStr, addrEndStr, portRangeStr ? portRangeStr : ""); } else { r = virAsprintf(&natRangeStr, "%s%s", addrStartStr, portRangeStr ? portRangeStr : ""); } if (r < 0) goto cleanup; virCommandAddArgList(cmd, "--jump", "SNAT", "--to-source", natRangeStr, NULL); } else { virCommandAddArgList(cmd, "--jump", "MASQUERADE", NULL); if (portRangeStr && portRangeStr[0]) virCommandAddArgList(cmd, "--to-ports", &portRangeStr[1], NULL); } ret = virCommandRun(cmd, NULL); cleanup: virCommandFree(cmd); VIR_FREE(networkstr); VIR_FREE(addrStartStr); VIR_FREE(addrEndStr); VIR_FREE(portRangeStr); VIR_FREE(natRangeStr); return ret; }
daemonSetupNetworking(virNetServerPtr srv, virNetServerPtr srvAdm, struct daemonConfig *config, const char *sock_path, const char *sock_path_ro, const char *sock_path_adm, bool ipsock, bool privileged) { virNetServerServicePtr svc = NULL; virNetServerServicePtr svcAdm = NULL; virNetServerServicePtr svcRO = NULL; virNetServerServicePtr svcTCP = NULL; #if WITH_GNUTLS virNetServerServicePtr svcTLS = NULL; #endif gid_t unix_sock_gid = 0; int unix_sock_ro_mask = 0; int unix_sock_rw_mask = 0; int unix_sock_adm_mask = 0; int ret = -1; unsigned int cur_fd = STDERR_FILENO + 1; unsigned int nfds = virGetListenFDs(); if (config->unix_sock_group) { if (virGetGroupID(config->unix_sock_group, &unix_sock_gid) < 0) return ret; } if (nfds > (sock_path_ro ? 2 : 1)) { VIR_ERROR(_("Too many (%u) FDs passed from caller"), nfds); return ret; } if (virStrToLong_i(config->unix_sock_ro_perms, NULL, 8, &unix_sock_ro_mask) != 0) { VIR_ERROR(_("Failed to parse mode '%s'"), config->unix_sock_ro_perms); goto cleanup; } if (virStrToLong_i(config->unix_sock_admin_perms, NULL, 8, &unix_sock_adm_mask) != 0) { VIR_ERROR(_("Failed to parse mode '%s'"), config->unix_sock_admin_perms); goto cleanup; } if (virStrToLong_i(config->unix_sock_rw_perms, NULL, 8, &unix_sock_rw_mask) != 0) { VIR_ERROR(_("Failed to parse mode '%s'"), config->unix_sock_rw_perms); goto cleanup; } if (!(svc = virNetServerServiceNewFDOrUNIX(sock_path, unix_sock_rw_mask, unix_sock_gid, config->auth_unix_rw, #if WITH_GNUTLS NULL, #endif false, config->max_queued_clients, config->max_client_requests, nfds, &cur_fd))) goto cleanup; if (sock_path_ro) { if (!(svcRO = virNetServerServiceNewFDOrUNIX(sock_path_ro, unix_sock_ro_mask, unix_sock_gid, config->auth_unix_ro, #if WITH_GNUTLS NULL, #endif true, config->max_queued_clients, config->max_client_requests, nfds, &cur_fd))) goto cleanup; } if (virNetServerAddService(srv, svc, config->mdns_adv && !ipsock ? "_libvirt._tcp" : NULL) < 0) goto cleanup; if (svcRO && virNetServerAddService(srv, svcRO, NULL) < 0) goto cleanup; /* Temporarily disabled */ if (sock_path_adm && false) { VIR_DEBUG("Registering unix socket %s", sock_path_adm); if (!(svcAdm = virNetServerServiceNewUNIX(sock_path_adm, unix_sock_adm_mask, unix_sock_gid, REMOTE_AUTH_NONE, #if WITH_GNUTLS NULL, #endif true, config->admin_max_queued_clients, config->admin_max_client_requests))) goto cleanup; if (virNetServerAddService(srvAdm, svcAdm, NULL) < 0) goto cleanup; } if (ipsock) { if (config->listen_tcp) { VIR_DEBUG("Registering TCP socket %s:%s", config->listen_addr, config->tcp_port); if (!(svcTCP = virNetServerServiceNewTCP(config->listen_addr, config->tcp_port, AF_UNSPEC, config->auth_tcp, #if WITH_GNUTLS NULL, #endif false, config->max_queued_clients, config->max_client_requests))) goto cleanup; if (virNetServerAddService(srv, svcTCP, config->mdns_adv ? "_libvirt._tcp" : NULL) < 0) goto cleanup; } #if WITH_GNUTLS if (config->listen_tls) { virNetTLSContextPtr ctxt = NULL; if (config->ca_file || config->cert_file || config->key_file) { if (!(ctxt = virNetTLSContextNewServer(config->ca_file, config->crl_file, config->cert_file, config->key_file, (const char *const*)config->tls_allowed_dn_list, config->tls_no_sanity_certificate ? false : true, config->tls_no_verify_certificate ? false : true))) goto cleanup; } else { if (!(ctxt = virNetTLSContextNewServerPath(NULL, !privileged, (const char *const*)config->tls_allowed_dn_list, config->tls_no_sanity_certificate ? false : true, config->tls_no_verify_certificate ? false : true))) goto cleanup; } VIR_DEBUG("Registering TLS socket %s:%s", config->listen_addr, config->tls_port); if (!(svcTLS = virNetServerServiceNewTCP(config->listen_addr, config->tls_port, AF_UNSPEC, config->auth_tls, ctxt, false, config->max_queued_clients, config->max_client_requests))) { virObjectUnref(ctxt); goto cleanup; } if (virNetServerAddService(srv, svcTLS, config->mdns_adv && !config->listen_tcp ? "_libvirt._tcp" : NULL) < 0) goto cleanup; virObjectUnref(ctxt); } #else (void)privileged; if (config->listen_tls) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("This libvirtd build does not support TLS")); goto cleanup; } #endif } #if WITH_SASL if (config->auth_unix_rw == REMOTE_AUTH_SASL || config->auth_unix_ro == REMOTE_AUTH_SASL || # if WITH_GNUTLS config->auth_tls == REMOTE_AUTH_SASL || # endif config->auth_tcp == REMOTE_AUTH_SASL) { saslCtxt = virNetSASLContextNewServer( (const char *const*)config->sasl_allowed_username_list); if (!saslCtxt) goto cleanup; } #endif ret = 0; cleanup: #if WITH_GNUTLS virObjectUnref(svcTLS); #endif virObjectUnref(svcTCP); virObjectUnref(svcRO); virObjectUnref(svcAdm); virObjectUnref(svc); return ret; }
/* * Try to extract loader and bhyve argv lists from a command line string. */ static int bhyveCommandLineToArgv(const char *nativeConfig, int *loader_argc, char ***loader_argv, int *bhyve_argc, char ***bhyve_argv) { const char *curr = NULL; char *nativeConfig_unescaped = NULL; const char *start; const char *next; char *line; char **lines = NULL; size_t i; size_t line_count = 0; size_t lines_alloc = 0; char **_bhyve_argv = NULL; char **_loader_argv = NULL; nativeConfig_unescaped = bhyveParseCommandLineUnescape(nativeConfig); if (nativeConfig_unescaped == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Failed to unescape command line string")); goto error; } curr = nativeConfig_unescaped; /* Iterate over string, splitting on sequences of '\n' */ while (curr && *curr != '\0') { start = curr; next = strchr(curr, '\n'); if (VIR_STRNDUP(line, curr, next ? next - curr : -1) < 0) goto error; if (VIR_RESIZE_N(lines, lines_alloc, line_count, 2) < 0) { VIR_FREE(line); goto error; } if (*line) lines[line_count++] = line; lines[line_count] = NULL; while (next && (*next == '\n' || *next == '\r' || STRPREFIX(next, "\r\n"))) next++; curr = next; } for (i = 0; i < line_count; i++) { curr = lines[i]; size_t j; char **arglist = NULL; size_t args_count = 0; size_t args_alloc = 0; /* iterate over each line, splitting on sequences of ' '. This code is * adapted from qemu/qemu_parse_command.c. */ while (curr && *curr != '\0') { char *arg; start = curr; if (*start == '\'') { if (start == curr) curr++; next = strchr(start + 1, '\''); } else if (*start == '"') { if (start == curr) curr++; next = strchr(start + 1, '"'); } else { next = strchr(start, ' '); } if (VIR_STRNDUP(arg, curr, next ? next - curr : -1) < 0) goto error; if (next && (*next == '\'' || *next == '"')) next++; if (VIR_RESIZE_N(arglist, args_alloc, args_count, 2) < 0) { VIR_FREE(arg); goto error; } arglist[args_count++] = arg; arglist[args_count] = NULL; while (next && c_isspace(*next)) next++; curr = next; } VIR_FREE(nativeConfig_unescaped); /* To prevent a memory leak here, only set the argument lists when * the first matching command is found. This shouldn't really be a * problem, since usually no multiple loaders or bhyverun commands * are specified (this wouldn't really be valid anyways). * Otherwise, later argument lists may be assigned to _argv without * freeing the earlier ones. */ if (!_bhyve_argv && STREQ(arglist[0], "/usr/sbin/bhyve")) { if ((VIR_REALLOC_N(_bhyve_argv, args_count + 1) < 0) || (!bhyve_argc)) goto error; for (j = 0; j < args_count; j++) _bhyve_argv[j] = arglist[j]; _bhyve_argv[j] = NULL; *bhyve_argc = args_count-1; VIR_FREE(arglist); } else if (!_loader_argv) { if ((VIR_REALLOC_N(_loader_argv, args_count + 1) < 0) || (!loader_argc)) goto error; for (j = 0; j < args_count; j++) _loader_argv[j] = arglist[j]; _loader_argv[j] = NULL; *loader_argc = args_count-1; VIR_FREE(arglist); } else { /* To prevent a use-after-free here, only free the argument list * when it is definitely not going to be used */ virStringFreeList(arglist); } } *loader_argv = _loader_argv; if (!(*bhyve_argv = _bhyve_argv)) goto error; virStringFreeList(lines); return 0; error: VIR_FREE(_loader_argv); VIR_FREE(_bhyve_argv); virStringFreeList(lines); return -1; }
int virPolkitCheckAuth(const char *actionid, pid_t pid, unsigned long long startTime ATTRIBUTE_UNUSED, uid_t uid, const char **details, bool allowInteraction ATTRIBUTE_UNUSED) { PolKitCaller *pkcaller = NULL; PolKitAction *pkaction = NULL; PolKitContext *pkcontext = NULL; PolKitError *pkerr = NULL; PolKitResult pkresult; DBusError err; DBusConnection *sysbus; int ret = -1; if (details) { virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Details not supported with polkit v0")); return -1; } if (!(sysbus = virDBusGetSystemBus())) goto cleanup; VIR_INFO("Checking PID %lld running as %d", (long long) pid, uid); dbus_error_init(&err); if (!(pkcaller = polkit_caller_new_from_pid(sysbus, pid, &err))) { VIR_DEBUG("Failed to lookup policy kit caller: %s", err.message); dbus_error_free(&err); goto cleanup; } if (!(pkaction = polkit_action_new())) { char ebuf[1024]; VIR_DEBUG("Failed to create polkit action %s", virStrerror(errno, ebuf, sizeof(ebuf))); goto cleanup; } polkit_action_set_action_id(pkaction, actionid); if (!(pkcontext = polkit_context_new()) || !polkit_context_init(pkcontext, &pkerr)) { char ebuf[1024]; VIR_DEBUG("Failed to create polkit context %s", (pkerr ? polkit_error_get_error_message(pkerr) : virStrerror(errno, ebuf, sizeof(ebuf)))); if (pkerr) polkit_error_free(pkerr); dbus_error_free(&err); goto cleanup; } # if HAVE_POLKIT_CONTEXT_IS_CALLER_AUTHORIZED pkresult = polkit_context_is_caller_authorized(pkcontext, pkaction, pkcaller, 0, &pkerr); if (pkerr && polkit_error_is_set(pkerr)) { VIR_DEBUG("Policy kit failed to check authorization %d %s", polkit_error_get_error_code(pkerr), polkit_error_get_error_message(pkerr)); goto cleanup; } # else pkresult = polkit_context_can_caller_do_action(pkcontext, pkaction, pkcaller); # endif if (pkresult != POLKIT_RESULT_YES) { VIR_DEBUG("Policy kit denied action %s from pid %lld, uid %d, result: %s", actionid, (long long) pid, uid, polkit_result_to_string_representation(pkresult)); ret = -2; goto cleanup; } VIR_DEBUG("Policy allowed action %s from pid %lld, uid %d", actionid, (long long)pid, (int)uid); ret = 0; cleanup: if (ret < 0) { virResetLastError(); virReportError(VIR_ERR_AUTH_FAILED, "%s", _("authentication failed")); } if (pkcontext) polkit_context_unref(pkcontext); if (pkcaller) polkit_caller_unref(pkcaller); if (pkaction) polkit_action_unref(pkaction); return ret; }
static int bhyveParsePCIDisk(virDomainDefPtr def, unsigned caps ATTRIBUTE_UNUSED, unsigned pcislot, unsigned pcibus, unsigned function, int bus, int device, unsigned *nvirtiodisk, unsigned *nahcidisk, char *config) { /* -s slot,virtio-blk|ahci-cd|ahci-hd,/path/to/file */ const char *separator = NULL; int idx = -1; virDomainDiskDefPtr disk = NULL; if (VIR_ALLOC(disk) < 0) goto cleanup; if (VIR_ALLOC(disk->src) < 0) goto error; disk->bus = bus; disk->device = device; disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; disk->info.addr.pci.slot = pcislot; disk->info.addr.pci.bus = pcibus; disk->info.addr.pci.function = function; if (STRPREFIX(config, "/dev/")) disk->src->type = VIR_STORAGE_TYPE_BLOCK; else disk->src->type = VIR_STORAGE_TYPE_FILE; if (!config) goto error; separator = strchr(config, ','); if (VIR_STRNDUP(disk->src->path, config, separator? separator - config : -1) < 0) goto error; if (bus == VIR_DOMAIN_DISK_BUS_VIRTIO) { idx = *nvirtiodisk; *nvirtiodisk += 1; if (VIR_STRDUP(disk->dst, "vda") < 0) goto error; } else if (bus == VIR_DOMAIN_DISK_BUS_SATA) { idx = *nahcidisk; *nahcidisk += 1; if (VIR_STRDUP(disk->dst, "sda") < 0) goto error; } if (idx > 'z' - 'a') { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("too many disks")); goto error; } disk->dst[2] = 'a' + idx; if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0) goto error; cleanup: return 0; error: virDomainDiskDefFree(disk); return -1; }
/* * virPolkitCheckAuth: * @actionid: permission to check * @pid: client process ID * @startTime: process start time, or 0 * @uid: client process user ID * @details: NULL terminated (key, value) pair list * @allowInteraction: true if auth prompts are allowed * * Check if a client is authenticated with polkit * * Returns 0 on success, -1 on failure, -2 on auth denied */ int virPolkitCheckAuth(const char *actionid, pid_t pid, unsigned long long startTime, uid_t uid, const char **details, bool allowInteraction) { DBusConnection *sysbus; DBusMessage *reply = NULL; char **retdetails = NULL; size_t nretdetails = 0; bool is_authorized; bool is_challenge; bool is_dismissed = false; size_t i; int ret = -1; if (!(sysbus = virDBusGetSystemBus())) goto cleanup; VIR_INFO("Checking PID %lld running as %d", (long long) pid, uid); if (virDBusCallMethod(sysbus, &reply, NULL, "org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority", "org.freedesktop.PolicyKit1.Authority", "CheckAuthorization", "(sa{sv})sa&{ss}us", "unix-process", 3, "pid", "u", (unsigned int)pid, "start-time", "t", startTime, "uid", "i", (int)uid, actionid, virStringListLength(details) / 2, details, allowInteraction, "" /* cancellation ID */) < 0) goto cleanup; if (virDBusMessageRead(reply, "(bba&{ss})", &is_authorized, &is_challenge, &nretdetails, &retdetails) < 0) goto cleanup; for (i = 0; i < (nretdetails / 2); i++) { if (STREQ(retdetails[(i * 2)], "polkit.dismissed") && STREQ(retdetails[(i * 2) + 1], "true")) is_dismissed = true; } VIR_DEBUG("is auth %d is challenge %d", is_authorized, is_challenge); if (is_authorized) { ret = 0; } else { ret = -2; if (is_dismissed) virReportError(VIR_ERR_AUTH_CANCELLED, "%s", _("user cancelled authentication process")); else if (is_challenge) virReportError(VIR_ERR_AUTH_UNAVAILABLE, _("no polkit agent available to authenticate " "action '%s'"), actionid); else virReportError(VIR_ERR_AUTH_FAILED, "%s", _("access denied by policy")); } cleanup: virStringListFreeCount(retdetails, nretdetails); virDBusMessageUnref(reply); return ret; }
/* * Parse the /usr/sbin/bhyve command line. */ static int bhyveParseBhyveCommandLine(virDomainDefPtr def, virDomainXMLOptionPtr xmlopt, unsigned caps, int argc, char **argv) { int c; const char optstr[] = "abehuwxACHIPSWYp:g:c:s:m:l:U:"; int vcpus = 1; size_t memory = 0; unsigned nahcidisks = 0; unsigned nvirtiodisks = 0; struct _getopt_data *parser; if (!argv) goto error; if (VIR_ALLOC(parser) < 0) goto error; while ((c = _getopt_internal_r(argc, argv, optstr, NULL, NULL, 0, parser, 0)) != -1) { switch (c) { case 'A': def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_TRISTATE_SWITCH_ON; break; case 'c': if (virStrToLong_i(parser->optarg, NULL, 10, &vcpus) < 0) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Failed to parse number of vCPUs")); goto error; } if (virDomainDefSetVcpusMax(def, vcpus, xmlopt) < 0) goto error; if (virDomainDefSetVcpus(def, vcpus) < 0) goto error; break; case 'l': if (bhyveParseBhyveLPCArg(def, caps, parser->optarg)) goto error; break; case 's': if (bhyveParseBhyvePCIArg(def, xmlopt, caps, &nahcidisks, &nvirtiodisks, parser->optarg)) goto error; break; case 'm': if (bhyveParseMemsize(parser->optarg, &memory)) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Failed to parse memory")); goto error; } if (def->mem.cur_balloon != 0 && def->mem.cur_balloon != memory) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Failed to parse memory: size mismatch")); goto error; } def->mem.cur_balloon = memory; virDomainDefSetMemoryTotal(def, memory); break; case 'I': /* While this flag was deprecated in FreeBSD r257423, keep checking * for it for backwards compatibility. */ def->features[VIR_DOMAIN_FEATURE_APIC] = VIR_TRISTATE_SWITCH_ON; break; case 'u': def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC; break; case 'U': if (virUUIDParse(parser->optarg, def->uuid) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Cannot parse UUID '%s'"), parser->optarg); goto error; } break; } } if (argc != parser->optind) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Failed to parse arguments for bhyve command")); goto error; } if (def->name == NULL) { if (VIR_STRDUP(def->name, argv[argc]) < 0) goto error; } else if (STRNEQ(def->name, argv[argc])) { /* the vm name of the loader and the bhyverun command differ, throw an * error here */ virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Failed to parse arguments: VM name mismatch")); goto error; } VIR_FREE(parser); return 0; error: VIR_FREE(parser); return -1; }
int qemuSetupCgroupForEmulator(virDomainObjPtr vm) { virBitmapPtr cpumask = NULL; virCgroupPtr cgroup_emulator = NULL; virDomainDefPtr def = vm->def; qemuDomainObjPrivatePtr priv = vm->privateData; unsigned long long period = vm->def->cputune.emulator_period; long long quota = vm->def->cputune.emulator_quota; if ((period || quota) && !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("cgroup cpu is required for scheduler tuning")); return -1; } /* * If CPU cgroup controller is not initialized here, then we need * neither period nor quota settings. And if CPUSET controller is * not initialized either, then there's nothing to do anyway. */ if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU) && !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) return 0; if (priv->cgroup == NULL) return 0; /* Not supported, so claim success */ if (virCgroupNewThread(priv->cgroup, VIR_CGROUP_THREAD_EMULATOR, 0, true, &cgroup_emulator) < 0) goto cleanup; if (virCgroupMoveTask(priv->cgroup, cgroup_emulator) < 0) goto cleanup; if (def->cputune.emulatorpin) cpumask = def->cputune.emulatorpin; else if (def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) cpumask = priv->autoCpuset; else if (def->cpumask) cpumask = def->cpumask; if (cpumask) { if (virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET) && qemuSetupCgroupCpusetCpus(cgroup_emulator, cpumask) < 0) goto cleanup; } if (period || quota) { if (virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU) && qemuSetupCgroupVcpuBW(cgroup_emulator, period, quota) < 0) goto cleanup; } virCgroupFree(&cgroup_emulator); return 0; cleanup: if (cgroup_emulator) { virCgroupRemove(cgroup_emulator); virCgroupFree(&cgroup_emulator); } return -1; }
static int testQemuMonitorJSONGetVersion(const void *data) { virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; qemuMonitorTestPtr test = qemuMonitorTestNew(true, xmlopt); int ret = -1; int major; int minor; int micro; char *package = NULL; if (!test) return -1; if (qemuMonitorTestAddItem(test, "query-version", "{ " " \"return\":{ " " \"qemu\":{ " " \"major\":1, " " \"minor\":2, " " \"micro\":3 " " }," " \"package\":\"\"" " }" "}") < 0) goto cleanup; if (qemuMonitorTestAddItem(test, "query-version", "{ " " \"return\":{ " " \"qemu\":{ " " \"major\":0, " " \"minor\":11, " " \"micro\":6 " " }," " \"package\":\"2.283.el6\"" " }" "}") < 0) goto cleanup; if (qemuMonitorGetVersion(qemuMonitorTestGetMonitor(test), &major, &minor, µ, &package) < 0) goto cleanup; if (major != 1) { virReportError(VIR_ERR_INTERNAL_ERROR, "Major %d was not 1", major); goto cleanup; } if (minor != 2) { virReportError(VIR_ERR_INTERNAL_ERROR, "Minor %d was not 2", major); goto cleanup; } if (micro != 3) { virReportError(VIR_ERR_INTERNAL_ERROR, "Micro %d was not 3", major); goto cleanup; } if (STRNEQ(package, "")) { virReportError(VIR_ERR_INTERNAL_ERROR, "Package %s was not ''", package); goto cleanup; } VIR_FREE(package); if (qemuMonitorGetVersion(qemuMonitorTestGetMonitor(test), &major, &minor, µ, &package) < 0) goto cleanup; if (major != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "Major %d was not 0", major); goto cleanup; } if (minor != 11) { virReportError(VIR_ERR_INTERNAL_ERROR, "Minor %d was not 11", major); goto cleanup; } if (micro != 6) { virReportError(VIR_ERR_INTERNAL_ERROR, "Micro %d was not 6", major); goto cleanup; } if (STRNEQ(package, "2.283.el6")) { virReportError(VIR_ERR_INTERNAL_ERROR, "Package %s was not '2.283.el6'", package); goto cleanup; } ret = 0; cleanup: qemuMonitorTestFree(test); VIR_FREE(package); return ret; }
int qemuSetupCgroupForIOThreads(virDomainObjPtr vm) { virCgroupPtr cgroup_iothread = NULL; qemuDomainObjPrivatePtr priv = vm->privateData; virDomainDefPtr def = vm->def; size_t i; unsigned long long period = vm->def->cputune.period; long long quota = vm->def->cputune.quota; char *mem_mask = NULL; virDomainNumatuneMemMode mem_mode; if ((period || quota) && !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("cgroup cpu is required for scheduler tuning")); return -1; } /* * If CPU cgroup controller is not initialized here, then we need * neither period nor quota settings. And if CPUSET controller is * not initialized either, then there's nothing to do anyway. */ if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU) && !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) return 0; /* We are trying to setup cgroups for CPU pinning, which can also be done * with virProcessSetAffinity, thus the lack of cgroups is not fatal here. */ if (priv->cgroup == NULL) return 0; if (virDomainNumatuneGetMode(vm->def->numa, -1, &mem_mode) == 0 && mem_mode == VIR_DOMAIN_NUMATUNE_MEM_STRICT && virDomainNumatuneMaybeFormatNodeset(vm->def->numa, priv->autoNodeset, &mem_mask, -1) < 0) goto cleanup; for (i = 0; i < def->niothreadids; i++) { /* IOThreads are numbered 1..n, although the array is 0..n-1, * so we will account for that here */ if (virCgroupNewThread(priv->cgroup, VIR_CGROUP_THREAD_IOTHREAD, def->iothreadids[i]->iothread_id, true, &cgroup_iothread) < 0) goto cleanup; /* move the thread for iothread to sub dir */ if (virCgroupAddTask(cgroup_iothread, def->iothreadids[i]->thread_id) < 0) goto cleanup; if (period || quota) { if (qemuSetupCgroupVcpuBW(cgroup_iothread, period, quota) < 0) goto cleanup; } if (mem_mask && virCgroupSetCpusetMems(cgroup_iothread, mem_mask) < 0) goto cleanup; /* Set iothreadpin in cgroup if iothreadpin xml is provided */ if (virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) { virBitmapPtr cpumask = NULL; if (def->iothreadids[i]->cpumask) cpumask = def->iothreadids[i]->cpumask; else if (def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) cpumask = priv->autoCpuset; else cpumask = def->cpumask; if (cpumask && qemuSetupCgroupCpusetCpus(cgroup_iothread, cpumask) < 0) goto cleanup; } virCgroupFree(&cgroup_iothread); } VIR_FREE(mem_mask); return 0; cleanup: if (cgroup_iothread) { virCgroupRemove(cgroup_iothread); virCgroupFree(&cgroup_iothread); } VIR_FREE(mem_mask); return -1; }
static int testQemuMonitorJSONGetStatus(const void *data) { virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; qemuMonitorTestPtr test = qemuMonitorTestNew(true, xmlopt); int ret = -1; bool running = false; virDomainPausedReason reason = 0; if (!test) return -1; if (qemuMonitorTestAddItem(test, "query-status", "{ " " \"return\": { " " \"status\": \"running\", " " \"singlestep\": false, " " \"running\": true " " } " "}") < 0) goto cleanup; if (qemuMonitorTestAddItem(test, "query-status", "{ " " \"return\": { " " \"singlestep\": false, " " \"running\": false " " } " "}") < 0) goto cleanup; if (qemuMonitorTestAddItem(test, "query-status", "{ " " \"return\": { " " \"status\": \"inmigrate\", " " \"singlestep\": false, " " \"running\": false " " } " "}") < 0) goto cleanup; if (qemuMonitorGetStatus(qemuMonitorTestGetMonitor(test), &running, &reason) < 0) goto cleanup; if (!running) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", "Running was not true"); goto cleanup; } if (reason != VIR_DOMAIN_PAUSED_UNKNOWN) { virReportError(VIR_ERR_INTERNAL_ERROR, "Reason was unexpectedly set to %d", reason); goto cleanup; } if (qemuMonitorGetStatus(qemuMonitorTestGetMonitor(test), &running, &reason) < 0) goto cleanup; if (running) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", "Running was not false"); goto cleanup; } if (reason != VIR_DOMAIN_PAUSED_UNKNOWN) { virReportError(VIR_ERR_INTERNAL_ERROR, "Reason was unexpectedly set to %d", reason); goto cleanup; } if (qemuMonitorGetStatus(qemuMonitorTestGetMonitor(test), &running, &reason) < 0) goto cleanup; if (running) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", "Running was not false"); goto cleanup; } if (reason != VIR_DOMAIN_PAUSED_MIGRATION) { virReportError(VIR_ERR_INTERNAL_ERROR, "Reason was unexpectedly set to %d", reason); goto cleanup; } ret = 0; cleanup: qemuMonitorTestFree(test); return ret; }
static int qemuInitCgroup(virQEMUDriverPtr driver, virDomainObjPtr vm, size_t nnicindexes, int *nicindexes) { int ret = -1; qemuDomainObjPrivatePtr priv = vm->privateData; virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); if (!cfg->privileged) goto done; if (!virCgroupAvailable()) goto done; virCgroupFree(&priv->cgroup); if (!vm->def->resource) { virDomainResourceDefPtr res; if (VIR_ALLOC(res) < 0) goto cleanup; if (VIR_STRDUP(res->partition, "/machine") < 0) { VIR_FREE(res); goto cleanup; } vm->def->resource = res; } if (vm->def->resource->partition[0] != '/') { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Resource partition '%s' must start with '/'"), vm->def->resource->partition); goto cleanup; } if (virCgroupNewMachine(vm->def->name, "qemu", cfg->privileged, vm->def->uuid, NULL, vm->pid, false, nnicindexes, nicindexes, vm->def->resource->partition, cfg->cgroupControllers, &priv->cgroup) < 0) { if (virCgroupNewIgnoreError()) goto done; goto cleanup; } done: ret = 0; cleanup: virObjectUnref(cfg); return ret; }
int virNetSocketNewListenTCP(const char *nodename, const char *service, virNetSocketPtr **retsocks, size_t *nretsocks) { virNetSocketPtr *socks = NULL; size_t nsocks = 0; struct addrinfo *ai = NULL; struct addrinfo hints; int fd = -1; int i; int addrInUse = false; *retsocks = NULL; *nretsocks = 0; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; hints.ai_socktype = SOCK_STREAM; int e = getaddrinfo(nodename, service, &hints, &ai); if (e != 0) { virReportError(VIR_ERR_SYSTEM_ERROR, _("Unable to resolve address '%s' service '%s': %s"), nodename, service, gai_strerror(e)); return -1; } struct addrinfo *runp = ai; while (runp) { virSocketAddr addr; memset(&addr, 0, sizeof(addr)); if ((fd = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol)) < 0) { virReportSystemError(errno, "%s", _("Unable to create socket")); goto error; } int opt = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { virReportSystemError(errno, "%s", _("Unable to enable port reuse")); goto error; } #ifdef IPV6_V6ONLY if (runp->ai_family == PF_INET6) { int on = 1; /* * Normally on Linux an INET6 socket will bind to the INET4 * address too. If getaddrinfo returns results with INET4 * first though, this will result in INET6 binding failing. * We can trivially cope with multiple server sockets, so * we force it to only listen on IPv6 */ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&on, sizeof(on)) < 0) { virReportSystemError(errno, "%s", _("Unable to force bind to IPv6 only")); goto error; } } #endif if (bind(fd, runp->ai_addr, runp->ai_addrlen) < 0) { if (errno != EADDRINUSE) { virReportSystemError(errno, "%s", _("Unable to bind to port")); goto error; } addrInUse = true; VIR_FORCE_CLOSE(fd); runp = runp->ai_next; continue; } addr.len = sizeof(addr.data); if (getsockname(fd, &addr.data.sa, &addr.len) < 0) { virReportSystemError(errno, "%s", _("Unable to get local socket name")); goto error; } VIR_DEBUG("%p f=%d f=%d", &addr, runp->ai_family, addr.data.sa.sa_family); if (VIR_EXPAND_N(socks, nsocks, 1) < 0) { virReportOOMError(); goto error; } if (!(socks[nsocks-1] = virNetSocketNew(&addr, NULL, false, fd, -1, 0))) goto error; runp = runp->ai_next; fd = -1; } if (nsocks == 0 && addrInUse) { virReportSystemError(EADDRINUSE, "%s", _("Unable to bind to port")); goto error; } freeaddrinfo(ai); *retsocks = socks; *nretsocks = nsocks; return 0; error: for (i = 0 ; i < nsocks ; i++) virObjectUnref(socks[i]); VIR_FREE(socks); freeaddrinfo(ai); VIR_FORCE_CLOSE(fd); return -1; }
int qemuSetupCgroupForVcpu(virDomainObjPtr vm) { virCgroupPtr cgroup_vcpu = NULL; qemuDomainObjPrivatePtr priv = vm->privateData; virDomainDefPtr def = vm->def; size_t i, j; unsigned long long period = vm->def->cputune.period; long long quota = vm->def->cputune.quota; char *mem_mask = NULL; virDomainNumatuneMemMode mem_mode; if ((period || quota) && !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("cgroup cpu is required for scheduler tuning")); return -1; } /* * If CPU cgroup controller is not initialized here, then we need * neither period nor quota settings. And if CPUSET controller is * not initialized either, then there's nothing to do anyway. */ if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU) && !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) return 0; /* We are trying to setup cgroups for CPU pinning, which can also be done * with virProcessSetAffinity, thus the lack of cgroups is not fatal here. */ if (priv->cgroup == NULL) return 0; if (priv->nvcpupids == 0 || priv->vcpupids[0] == vm->pid) { /* If we don't know VCPU<->PID mapping or all vcpu runs in the same * thread, we cannot control each vcpu. */ return 0; } if (virDomainNumatuneGetMode(vm->def->numa, -1, &mem_mode) == 0 && mem_mode == VIR_DOMAIN_NUMATUNE_MEM_STRICT && virDomainNumatuneMaybeFormatNodeset(vm->def->numa, priv->autoNodeset, &mem_mask, -1) < 0) goto cleanup; for (i = 0; i < priv->nvcpupids; i++) { virCgroupFree(&cgroup_vcpu); if (virCgroupNewThread(priv->cgroup, VIR_CGROUP_THREAD_VCPU, i, true, &cgroup_vcpu) < 0) goto cleanup; /* move the thread for vcpu to sub dir */ if (virCgroupAddTask(cgroup_vcpu, priv->vcpupids[i]) < 0) goto cleanup; if (mem_mask && virCgroupSetCpusetMems(cgroup_vcpu, mem_mask) < 0) goto cleanup; if (period || quota) { if (qemuSetupCgroupVcpuBW(cgroup_vcpu, period, quota) < 0) goto cleanup; } /* Set vcpupin in cgroup if vcpupin xml is provided */ if (virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) { virBitmapPtr cpumap = NULL; /* try to use the default cpu maps */ if (vm->def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) cpumap = priv->autoCpuset; else cpumap = vm->def->cpumask; /* lookup a more specific pinning info */ for (j = 0; j < def->cputune.nvcpupin; j++) { if (def->cputune.vcpupin[j]->id == i) { cpumap = def->cputune.vcpupin[j]->cpumask; break; } } if (!cpumap) continue; if (qemuSetupCgroupCpusetCpus(cgroup_vcpu, cpumap) < 0) goto cleanup; } } virCgroupFree(&cgroup_vcpu); VIR_FREE(mem_mask); return 0; cleanup: if (cgroup_vcpu) { virCgroupRemove(cgroup_vcpu); virCgroupFree(&cgroup_vcpu); } VIR_FREE(mem_mask); return -1; }
static int openvzReadFSConf(virDomainDefPtr def, int veid) { int ret; virDomainFSDefPtr fs = NULL; char *veid_str = NULL; char *temp = NULL; const char *param; unsigned long long barrier, limit; ret = openvzReadVPSConfigParam(veid, "OSTEMPLATE", &temp); if (ret < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not read 'OSTEMPLATE' from config for container %d"), veid); goto error; } else if (ret > 0) { if (VIR_ALLOC(fs) < 0) goto no_memory; fs->type = VIR_DOMAIN_FS_TYPE_TEMPLATE; fs->src = strdup(temp); } else { /* OSTEMPLATE was not found, VE was booted from a private dir directly */ ret = openvzReadVPSConfigParam(veid, "VE_PRIVATE", &temp); if (ret <= 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not read 'VE_PRIVATE' from config for container %d"), veid); goto error; } if (VIR_ALLOC(fs) < 0) goto no_memory; if (virAsprintf(&veid_str, "%d", veid) < 0) goto no_memory; fs->type = VIR_DOMAIN_FS_TYPE_MOUNT; fs->src = openvz_replace(temp, "$VEID", veid_str); VIR_FREE(veid_str); } fs->dst = strdup("/"); param = "DISKSPACE"; ret = openvzReadVPSConfigParam(veid, param, &temp); if (ret > 0) { if (openvzParseBarrierLimit(temp, &barrier, &limit)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not read '%s' from config for container %d"), param, veid); goto error; } else { /* Ensure that we can multiply by 1024 without overflowing. */ if (barrier > ULLONG_MAX / 1024 || limit > ULLONG_MAX / 1024) { virReportSystemError(VIR_ERR_OVERFLOW, "%s", _("Unable to parse quota")); goto error; } fs->space_soft_limit = barrier * 1024; /* unit is bytes */ fs->space_hard_limit = limit * 1024; /* unit is bytes */ } } if (fs->src == NULL || fs->dst == NULL) goto no_memory; if (VIR_REALLOC_N(def->fss, def->nfss + 1) < 0) goto no_memory; def->fss[def->nfss++] = fs; fs = NULL; VIR_FREE(temp); return 0; no_memory: virReportOOMError(); error: VIR_FREE(temp); virDomainFSDefFree(fs); return -1; }
/** * cpuBaseline: * * @cpus: list of host CPU definitions * @ncpus: number of CPUs in @cpus * @models: list of CPU models that can be considered for the baseline CPU * @nmodels: number of CPU models in @models * @flags: bitwise-OR of virConnectBaselineCPUFlags * * Computes the most feature-rich CPU which is compatible with all given * host CPUs. If @models array is NULL, all models supported by libvirt will * be considered when computing the baseline CPU model, otherwise the baseline * CPU model will be one of the provided CPU @models. * * If @flags includes VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES then libvirt * will explicitly list all CPU features that are part of the host CPU, * without this flag features that are part of the CPU model will not be * listed. * * Returns baseline CPU definition or NULL on error. */ virCPUDefPtr cpuBaseline(virCPUDefPtr *cpus, unsigned int ncpus, const char **models, unsigned int nmodels, unsigned int flags) { struct cpuArchDriver *driver; size_t i; VIR_DEBUG("ncpus=%u, nmodels=%u", ncpus, nmodels); if (cpus) { for (i = 0; i < ncpus; i++) VIR_DEBUG("cpus[%zu]=%p", i, cpus[i]); } if (models) { for (i = 0; i < nmodels; i++) VIR_DEBUG("models[%zu]=%s", i, NULLSTR(models[i])); } if (cpus == NULL && ncpus != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nonzero ncpus doesn't match with NULL cpus")); return NULL; } if (ncpus < 1) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("No CPUs given")); return NULL; } for (i = 0; i < ncpus; i++) { if (!cpus[i]) { virReportError(VIR_ERR_INVALID_ARG, _("invalid CPU definition at index %zu"), i); return NULL; } if (!cpus[i]->model) { virReportError(VIR_ERR_INVALID_ARG, _("no CPU model specified at index %zu"), i); return NULL; } } if (models == NULL && nmodels != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nonzero nmodels doesn't match with NULL models")); return NULL; } if ((driver = cpuGetSubDriver(cpus[0]->arch)) == NULL) return NULL; if (driver->baseline == NULL) { virReportError(VIR_ERR_NO_SUPPORT, _("cannot compute baseline CPU of %s architecture"), virArchToString(cpus[0]->arch)); return NULL; } return driver->baseline(cpus, ncpus, models, nmodels, flags); }