Implement the qemud's network stubs, but don't actually do anything when starting a network. Note, an example XML file would be: <network> <name>TestNetwork</name> <uuid>ac57b808-bfdd-4aa3-8da8-0bd4ac1faceb</uuid> <ip address="10.0.0.1" netmask="255.255.255.0"> <dhcp> <range start="10.0.0.16" end="10.0.0.32" /> <range start="10.0.0.128" end="10.0.0.254" /> </dhcp> </ip> </network> Signed-off-by: Mark McLoughlin <markmc@xxxxxxxxxx> Index: libvirt-foo/qemud/conf.c =================================================================== --- libvirt-foo.orig/qemud/conf.c 2007-02-14 14:57:31.000000000 +0000 +++ libvirt-foo.orig/qemud/conf.c 2007-02-14 14:57:31.000000000 +0000 @@ -1098,17 +1098,186 @@ struct qemud_vm *qemudLoadConfigXML(stru } +void qemudFreeNetwork(struct qemud_network *network) { + free(network); +} + + +static int qemudSaveNetworkConfig(struct qemud_server *server, + struct qemud_network *network) { + char *xml; + int fd, ret = -1; + int towrite; + + if (!(xml = qemudGenerateNetworkXML(server, network))) { + return -1; + } + + if (qemudEnsureConfigDir(server, server->networkConfigDir) < 0) { + goto cleanup; + } + + if ((fd = open(network->configFile, + O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR )) < 0) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot create config file %s", network->configFile); + goto cleanup; + } + + towrite = strlen(xml); + if (write(fd, xml, towrite) != towrite) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot write config file %s", network->configFile); + goto cleanup; + } + + if (close(fd) < 0) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot save config file %s", network->configFile); + goto cleanup; + } + + ret = 0; + + cleanup: + + free(xml); + + return ret; +} + + +static int qemudParseNetworkXML(struct qemud_server *server, + xmlDocPtr xml, + struct qemud_network *network) { + xmlNodePtr root = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlXPathObjectPtr obj = NULL; + + /* Prepare parser / xpath context */ + root = xmlDocGetRootElement(xml); + if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "network"))) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s", "incorrect root element"); + goto error; + } + + ctxt = xmlXPathNewContext(xml); + if (ctxt == NULL) { + qemudReportError(server, VIR_ERR_NO_MEMORY, "xmlXPathContext"); + goto error; + } + + + /* Extract network name */ + obj = xmlXPathEval(BAD_CAST "string(/network/name[1])", ctxt); + if ((obj == NULL) || (obj->type != XPATH_STRING) || + (obj->stringval == NULL) || (obj->stringval[0] == 0)) { + qemudReportError(server, VIR_ERR_NO_NAME, NULL); + goto error; + } + if (strlen((const char *)obj->stringval) >= (QEMUD_MAX_NAME_LEN-1)) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s", "network name length too long"); + goto error; + } + strcpy(network->def.name, (const char *)obj->stringval); + xmlXPathFreeObject(obj); + + + /* Extract network uuid */ + obj = xmlXPathEval(BAD_CAST "string(/network/uuid[1])", ctxt); + if ((obj == NULL) || (obj->type != XPATH_STRING) || + (obj->stringval == NULL) || (obj->stringval[0] == 0)) { + /* XXX auto-generate a UUID */ + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s", "missing uuid element"); + goto error; + } + if (qemudParseUUID((const char *)obj->stringval, network->def.uuid) < 0) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s", "malformed uuid element"); + goto error; + } + xmlXPathFreeObject(obj); + + xmlXPathFreeContext(ctxt); + + return 0; + + error: + /* XXX free all the stuff in the qemud_network struct, or leave it upto + the caller ? */ + if (obj) + xmlXPathFreeObject(obj); + if (ctxt) + xmlXPathFreeContext(ctxt); + return -1; +} + + +struct qemud_network *qemudLoadNetworkConfigXML(struct qemud_server *server, + const char *file, + const char *doc, + int save) { + struct qemud_network *network = NULL; + xmlDocPtr xml; + + if (!(xml = xmlReadDoc(BAD_CAST doc, file ? file : "network.xml", NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) { + qemudReportError(server, VIR_ERR_XML_ERROR, NULL); + return NULL; + } + + if (!(network = calloc(1, sizeof(struct qemud_network)))) { + qemudReportError(server, VIR_ERR_NO_MEMORY, "network"); + return NULL; + } + + if (qemudParseNetworkXML(server, xml, network) < 0) { + xmlFreeDoc(xml); + qemudFreeNetwork(network); + return NULL; + } + xmlFreeDoc(xml); + + if (qemudFindNetworkByUUID(server, network->def.uuid) || + qemudFindNetworkByName(server, network->def.name)) { + qemudReportError(server, VIR_ERR_NETWORK_EXIST, network->def.name); + qemudFreeNetwork(network); + return NULL; + } + + if (file) { + strncpy(network->configFile, file, PATH_MAX); + network->configFile[PATH_MAX-1] = '\0'; + } else { + if (save) { + if (qemudMakeConfigPath(server->networkConfigDir, network->def.name, ".xml", network->configFile, PATH_MAX) < 0) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot construct config file path"); + qemudFreeNetwork(network); + return NULL; + } + + if (qemudSaveNetworkConfig(server, network) < 0) { + qemudFreeNetwork(network); + return NULL; + } + } else { + network->configFile[0] = '\0'; + } + } + + return network; +} + + /* Load a guest from its persistent config file */ static void qemudLoadConfig(struct qemud_server *server, - const char *file) { + const char *file, + int isGuest) { FILE *fh; struct stat st; - struct qemud_vm *vm; char xml[QEMUD_MAX_XML_LEN]; int ret; if (!(fh = fopen(file, "r"))) { - qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot open guest config file %s", file); + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot open config file %s", file); return; } @@ -1118,7 +1287,7 @@ static void qemudLoadConfig(struct qemud } if (st.st_size >= QEMUD_MAX_XML_LEN) { - qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "guest config too large in file %s", file); + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "config too large in file %s", file); goto cleanup; } @@ -1128,10 +1297,20 @@ static void qemudLoadConfig(struct qemud } xml[st.st_size] = '\0'; - if ((vm = qemudLoadConfigXML(server, file, xml, 1))) { - vm->next = server->inactivevms; - server->inactivevms = vm; - server->ninactivevms++; + if (isGuest) { + struct qemud_vm *vm; + if ((vm = qemudLoadConfigXML(server, file, xml, 1))) { + vm->next = server->inactivevms; + server->inactivevms = vm; + server->ninactivevms++; + } + } else { + struct qemud_network *network; + if ((network = qemudLoadNetworkConfigXML(server, file, xml, 1))) { + network->next = server->inactivenetworks; + server->inactivenetworks = network; + server->ninactivenetworks++; + } } cleanup: @@ -1141,7 +1320,8 @@ static void qemudLoadConfig(struct qemud static int qemudScanConfigDir(struct qemud_server *server, - const char *configDir) { + const char *configDir, + int isGuest) { DIR *dir; struct dirent *entry; @@ -1159,7 +1339,7 @@ int qemudScanConfigDir(struct qemud_serv if (qemudMakeConfigPath(configDir, entry->d_name, NULL, file, PATH_MAX) < 0) continue; - qemudLoadConfig(server, file); + qemudLoadConfig(server, file, isGuest); } closedir(dir); @@ -1169,7 +1349,9 @@ int qemudScanConfigDir(struct qemud_serv /* Scan for all guest and network config files */ int qemudScanConfigs(struct qemud_server *server) { - return qemudScanConfigDir(server, server->configDir); + if (qemudScanConfigDir(server, server->configDir, 0) < 0) + return -1; + return qemudScanConfigDir(server, server->networkConfigDir, 1); } /* Simple grow-on-demand string buffer */ @@ -1424,19 +1606,54 @@ char *qemudGenerateXML(struct qemud_serv } -int qemudDeleteConfigXML(struct qemud_server *server, struct qemud_vm *vm) { - if (!vm->configFile[0]) { - qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "no config file for guest %s", vm->def.name); +char *qemudGenerateNetworkXML(struct qemud_server *server, + struct qemud_network *network) { + struct qemudBuffer buf; + unsigned char *uuid; + + buf.len = QEMUD_MAX_XML_LEN; + buf.used = 0; + buf.data = malloc(buf.len); + + if (qemudBufferPrintf(&buf, "<network>\n") < 0) + goto no_memory; + + if (qemudBufferPrintf(&buf, " <name>%s</name>\n", network->def.name) < 0) + goto no_memory; + + uuid = network->def.uuid; + if (qemudBufferPrintf(&buf, " <uuid>%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x</uuid>\n", + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]) < 0) + goto no_memory; + + if (qemudBufferAdd(&buf, "</network>\n") < 0) + goto no_memory; + + return buf.data; + + no_memory: + qemudReportError(server, VIR_ERR_NO_MEMORY, "xml"); + free(buf.data); + return NULL; +} + + +int qemudDeleteConfig(struct qemud_server *server, + const char *configFile, + const char *name) { + if (!configFile[0]) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "no config file for %s", name); return -1; } - if (unlink(vm->configFile) < 0) { - qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot remove config for guest %s", vm->def.name); + if (unlink(configFile) < 0) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot remove config for %s", name); return -1; } - vm->configFile[0] = '\0'; - return 0; } Index: libvirt-foo/qemud/conf.h =================================================================== --- libvirt-foo.orig/qemud/conf.h 2007-02-14 15:06:41.000000000 +0000 +++ libvirt-foo.orig/qemud/conf.h 2007-02-14 15:06:41.000000000 +0000 @@ -30,18 +30,26 @@ int qemudBuildCommandLine(struct qemud_s struct qemud_vm *vm, char ***argv); +int qemudScanConfigs(struct qemud_server *server); +int qemudDeleteConfig(struct qemud_server *server, + const char *configFile, + const char *name); + void qemudFreeVM(struct qemud_vm *vm); struct qemud_vm *qemudLoadConfigXML(struct qemud_server *server, const char *file, const char *doc, int persist); -int qemudScanConfigs(struct qemud_server *server); char *qemudGenerateXML(struct qemud_server *server, struct qemud_vm *vm); -int qemudDeleteConfigXML(struct qemud_server *server, - struct qemud_vm *vm); - +void qemudFreeNetwork(struct qemud_network *network); +struct qemud_network *qemudLoadNetworkConfigXML(struct qemud_server *server, + const char *file, + const char *doc, + int persist); +char *qemudGenerateNetworkXML(struct qemud_server *server, + struct qemud_network *network); #endif Index: libvirt-foo/qemud/driver.c =================================================================== --- libvirt-foo.orig/qemud/driver.c 2007-02-14 15:46:58.000000000 +0000 +++ libvirt-foo.orig/qemud/driver.c 2007-02-14 15:46:58.000000000 +0000 @@ -522,9 +522,11 @@ int qemudDomainUndefine(struct qemud_ser return -1; } - if (qemudDeleteConfigXML(server, vm) < 0) + if (qemudDeleteConfig(server, vm->configFile, vm->def.name) < 0) return -1; + vm->configFile[0] = '\0'; + while (curr) { if (curr == vm) { if (prev) { @@ -547,67 +549,198 @@ int qemudDomainUndefine(struct qemud_ser struct qemud_network *qemudFindNetworkByUUID(const struct qemud_server *server, const unsigned char *uuid) { - server = NULL; uuid = NULL; + struct qemud_network *network = server->activenetworks; + + while (network) { + if (!memcmp(network->def.uuid, uuid, QEMUD_UUID_RAW_LEN)) + return network; + network = network->next; + } + + network = server->inactivenetworks; + while (network) { + if (!memcmp(network->def.uuid, uuid, QEMUD_UUID_RAW_LEN)) + return network; + network = network->next; + } + return NULL; } struct qemud_network *qemudFindNetworkByName(const struct qemud_server *server, const char *name) { - server = NULL; name = NULL; + struct qemud_network *network = server->activenetworks; + + while (network) { + if (!strcmp(network->def.name, name)) + return network; + network = network->next; + } + + network = server->inactivenetworks; + while (network) { + if (!strcmp(network->def.name, name)) + return network; + network = network->next; + } + return NULL; } int qemudNumNetworks(struct qemud_server *server) { - server = NULL; - return 0; + return server->nactivenetworks; } int qemudListNetworks(struct qemud_server *server, char *const*names, int nnames) { - server = NULL; names = NULL; nnames = 0; - return 0; + struct qemud_network *network = server->activenetworks; + int got = 0; + while (network && got < nnames) { + strncpy(names[got], network->def.name, QEMUD_MAX_NAME_LEN-1); + names[got][QEMUD_MAX_NAME_LEN-1] = '\0'; + network = network->next; + got++; + } + return got; } int qemudNumDefinedNetworks(struct qemud_server *server) { - server = NULL; - return 0; + return server->ninactivenetworks; } int qemudListDefinedNetworks(struct qemud_server *server, char *const*names, int nnames) { - server = NULL; names = NULL; nnames = 0; - return 0; + struct qemud_network *network = server->inactivenetworks; + int got = 0; + while (network && got < nnames) { + strncpy(names[got], network->def.name, QEMUD_MAX_NAME_LEN-1); + names[got][QEMUD_MAX_NAME_LEN-1] = '\0'; + network = network->next; + got++; + } + return got; } struct qemud_network *qemudNetworkCreate(struct qemud_server *server, const char *xml) { - server = NULL; xml = NULL; - return NULL; + struct qemud_network *network; + + if (!(network = qemudLoadNetworkConfigXML(server, NULL, xml, 0))) { + return NULL; + } + + if (qemudStartNetworkDaemon(server, network) < 0) { + qemudFreeNetwork(network); + return NULL; + } + + network->next = server->activenetworks; + server->activenetworks = network; + server->nactivenetworks++; + + return network; } struct qemud_network *qemudNetworkDefine(struct qemud_server *server, const char *xml) { - server = NULL; xml = NULL; - return NULL; + struct qemud_network *network; + + if (!(network = qemudLoadNetworkConfigXML(server, NULL, xml, 1))) { + return NULL; + } + + network->next = server->inactivenetworks; + server->inactivenetworks = network; + server->ninactivenetworks++; + + return network; } int qemudNetworkUndefine(struct qemud_server *server, const unsigned char *uuid) { - qemudReportError(server, VIR_ERR_INVALID_NETWORK, "no network with matching uuid"); - uuid = NULL; - return -1; + struct qemud_network *network = qemudFindNetworkByUUID(server, uuid); + struct qemud_network *prev = NULL, *curr = server->inactivenetworks; + + if (!network) { + qemudReportError(server, VIR_ERR_INVALID_DOMAIN, "no network with matching uuid"); + return -1; + } + + if (qemudDeleteConfig(server, network->configFile, network->def.name) < 0) + return -1; + + network->configFile[0] = '\0'; + + while (curr) { + if (curr == network) { + if (prev) { + prev->next = curr->next; + } else { + server->inactivenetworks = curr->next; + } + server->ninactivenetworks--; + break; + } + + prev = curr; + curr = curr->next; + } + + qemudFreeNetwork(network); + + return 0; } int qemudNetworkStart(struct qemud_server *server, struct qemud_network *network) { - server = NULL; network = NULL; - return 1; + struct qemud_network *prev = NULL, *curr = server->inactivenetworks; + if (qemudStartNetworkDaemon(server, network) < 0) { + return 1; + } + + while (curr) { + if (curr == network) { + if (prev) + prev->next = curr->next; + else + server->inactivenetworks = curr->next; + server->ninactivenetworks--; + break; + } + prev = curr; + curr = curr->next; + } + + network->next = server->activenetworks; + server->activenetworks = network; + server->nactivenetworks++; + + return 0; } int qemudNetworkDestroy(struct qemud_server *server, const unsigned char *uuid) { - uuid = NULL; - qemudReportError(server, VIR_ERR_INVALID_NETWORK, "no network with matching uuid"); - return -1; + struct qemud_network *network = qemudFindNetworkByUUID(server, uuid); + if (!network) { + qemudReportError(server, VIR_ERR_INVALID_NETWORK, "no network with matching uuid"); + return -1; + } + + if (qemudShutdownNetworkDaemon(server, network) < 0) + return -1; + + return 0; } int qemudNetworkDumpXML(struct qemud_server *server, const unsigned char *uuid, char *xml, int xmllen) { - qemudReportError(server, VIR_ERR_INVALID_NETWORK, "no network with matching uuid"); - uuid = NULL; xml = NULL; xmllen = 0; - return -1; + struct qemud_network *network = qemudFindNetworkByUUID(server, uuid); + char *networkxml; + if (!network) { + qemudReportError(server, VIR_ERR_INVALID_NETWORK, "no network with matching uuid"); + return -1; + } + + networkxml = qemudGenerateNetworkXML(server, network); + if (!networkxml) + return -1; + + strncpy(xml, networkxml, xmllen); + xml[xmllen-1] = '\0'; + + return 0; } /* Index: libvirt-foo/qemud/internal.h =================================================================== --- libvirt-foo.orig/qemud/internal.h 2007-02-14 15:46:58.000000000 +0000 +++ libvirt-foo.orig/qemud/internal.h 2007-02-14 15:46:58.000000000 +0000 @@ -207,6 +207,8 @@ struct qemud_network_def { /* Virtual Network runtime state */ struct qemud_network { + char configFile[PATH_MAX]; + struct qemud_network_def def; struct qemud_network *next; }; @@ -243,7 +245,12 @@ struct qemud_server { int ninactivevms; struct qemud_vm *inactivevms; int nextvmid; + int nactivenetworks; + struct qemud_network *activenetworks; + int ninactivenetworks; + struct qemud_network *inactivenetworks; char configDir[PATH_MAX]; + char networkConfigDir[PATH_MAX]; char errorMessage[QEMUD_MAX_ERROR_LEN]; int errorCode; }; @@ -254,6 +261,13 @@ int qemudStartVMDaemon(struct qemud_serv int qemudShutdownVMDaemon(struct qemud_server *server, struct qemud_vm *vm); +int qemudStartNetworkDaemon(struct qemud_server *server, + struct qemud_network *network); + +int qemudShutdownNetworkDaemon(struct qemud_server *server, + struct qemud_network *network); + + #endif /* Index: libvirt-foo/qemud/qemud.c =================================================================== --- libvirt-foo.orig/qemud/qemud.c 2007-02-14 14:53:23.000000000 +0000 +++ libvirt-foo.orig/qemud/qemud.c 2007-02-14 14:53:23.000000000 +0000 @@ -251,6 +251,9 @@ static struct qemud_server *qemudInitial if (snprintf(server->configDir, sizeof(server->configDir), "%s/qemud", SYSCONF_DIR) >= (int)sizeof(server->configDir)) { goto cleanup; } + if (snprintf(server->networkConfigDir, sizeof(server->networkConfigDir), "%s/qemud/networks", SYSCONF_DIR) >= (int)sizeof(server->networkConfigDir)) { + goto cleanup; + } } else { struct passwd *pw; int uid; @@ -264,8 +267,13 @@ static struct qemud_server *qemudInitial if (snprintf(server->configDir, sizeof(server->configDir), "%s/.qemud", pw->pw_dir) >= (int)sizeof(server->configDir)) { goto cleanup; } + + if (snprintf(server->networkConfigDir, sizeof(server->networkConfigDir), "%s/.qemud.d/networks", pw->pw_dir) >= (int)sizeof(server->networkConfigDir)) { + goto cleanup; + } } + if (qemudListen(server, sys) < 0) { goto cleanup; } @@ -696,6 +704,20 @@ static int qemudDispatchVMFailure(struct } +int qemudStartNetworkDaemon(struct qemud_server *server, + struct qemud_network *network) { + server = NULL; network = NULL; + return 0; +} + + +int qemudShutdownNetworkDaemon(struct qemud_server *server, + struct qemud_network *network) { + server = NULL; network = NULL; + return 0; +} + + static int qemudDispatchPoll(struct qemud_server *server, struct pollfd *fds) { struct qemud_socket *sock = server->sockets; struct qemud_client *client = server->clients; --