diff --git a/ChangeLog b/ChangeLog index af02d845da8cd5ba25da560e7e5df6a3e4aea4c5..ef87988482131946720f6d007260c23d5a5d6204 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Mon Oct 22 22:27:40 CEST 2007 Daniel Veillard + + * docs/format.html docs/libvir.html: documentation cleaups + from Jim Paris + Mon Oct 22 15:05:30 CEST 2007 Daniel Veillard * src/xend_internal.c: update to cpuset parsing code for NUMA diff --git a/docs/format.html b/docs/format.html index efdbcde19457fff5e2550fd74754c11c3aab1d94..26a4c3d9c81cfc1b84f56ad6eaf00b5d690ed206 100644 --- a/docs/format.html +++ b/docs/format.html @@ -230,7 +230,7 @@ support a variety of options:

  1. Userspace SLIRP stack
    <interface type='user'/>
     <interface type='user'>                                                  
    -  <mac address="11:22:33:44:55:66:/>                                     
    +  <mac address="11:22:33:44:55:66"/>                                     
     </interface>
         
  2. @@ -253,7 +253,7 @@ support a variety of options:

    1. Userspace SLIRP stack <interface type='network'> <source network='default'/> <target dev='vnet7'/> - <mac address="11:22:33:44:55:66:/> + <mac address="11:22:33:44:55:66"/> </interface>
    2. @@ -273,12 +273,8 @@ support a variety of options:

      1. Userspace SLIRP stack <interface type='bridge'> <source dev='br0'/> <target dev='vnet7'/> - <mac address="11:22:33:44:55:66:/> -</interface> <interface type='bridge'> - <source dev='br0'/> - <target dev='vnet7'/> - <mac address="11:22:33:44:55:66:/> - </interface> + <mac address="11:22:33:44:55:66"/> +</interface>
      2. Generic connection to LAN

        Provides a means for the administrator to execute an arbitrary script diff --git a/docs/libvir.html b/docs/libvir.html index 22bb1681a22a425e16fcd9a63fe313a74058f11d..571b9c1c33d722f5bf96642b1953e7f438dd6aca 100644 --- a/docs/libvir.html +++ b/docs/libvir.html @@ -964,7 +964,7 @@ support a variety of options:

        <interface type='user'/>
         <interface type='user'>                                                  
        -  <mac address="11:22:33:44:55:66:/>                                     
        +  <mac address="11:22:33:44:55:66"/>                                     
         </interface>
             
      3. @@ -987,7 +987,7 @@ support a variety of options:

        <interface type='network'> <source network='default'/> <target dev='vnet7'/> - <mac address="11:22:33:44:55:66:/> + <mac address="11:22:33:44:55:66"/> </interface> @@ -1007,12 +1007,8 @@ support a variety of options:

        <interface type='bridge'> <source dev='br0'/> <target dev='vnet7'/> - <mac address="11:22:33:44:55:66:/> -</interface> <interface type='bridge'> - <source dev='br0'/> - <target dev='vnet7'/> - <mac address="11:22:33:44:55:66:/> - </interface> + <mac address="11:22:33:44:55:66"/> +</interface>
      4. Generic connection to LAN

        Provides a means for the administrator to execute an arbitrary script diff --git a/src/xen_internal.c b/src/xen_internal.c index 8cc5a5cf805f39613178457805e795f8b7861c7e..0bc956e335ad781cf52178374624c5347e7932fd 100644 --- a/src/xen_internal.c +++ b/src/xen_internal.c @@ -3035,24 +3035,27 @@ xenHypervisorNodeGetCellsFreeMemory(virConnectPtr conn, unsigned long long *free xen_op_v2_sys op_sys; int i, j, ret; xenUnifiedPrivatePtr priv; - static int nbNodeCells = -1; - virNodeInfo nodeInfo; + int nbNodeCells; + if (conn == NULL) { + virXenErrorFunc (VIR_ERR_INVALID_ARG, __FUNCTION__, + "invalid argument", 0); + return -1; + } - if (nbNodeCells == -1) { - if (xenDaemonNodeGetInfo(conn, &nodeInfo)) { - virXenErrorFunc (VIR_ERR_XEN_CALL, __FUNCTION__, - "cannot determine actual number of cells",0); - return -1; - } - nbNodeCells = nodeInfo.nodes; + nbNodeCells = xenNbCells(conn); + if (nbNodeCells < 0) { + virXenErrorFunc (VIR_ERR_XEN_CALL, __FUNCTION__, + "cannot determine actual number of cells",0); + return(-1); } - if ((conn == NULL) || (maxCells < 1) || (startCell >= nbNodeCells)) { + if ((maxCells < 1) || (startCell >= nbNodeCells)) { virXenErrorFunc (VIR_ERR_INVALID_ARG, __FUNCTION__, "invalid argument", 0); return -1; } + /* * Support only sys_interface_version >=4 */ diff --git a/src/xen_unified.c b/src/xen_unified.c index b5c27e443c49627ef58711b1997bb50caf593763..760ec5282f84c7d78c297feb22e6933a3006bc25 100644 --- a/src/xen_unified.c +++ b/src/xen_unified.c @@ -37,6 +37,9 @@ #include "xs_internal.h" #include "xm_internal.h" +static int +xenUnifiedNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info); + /* The five Xen drivers below us. */ static struct xenUnifiedDriver *drivers[XEN_UNIFIED_NR_DRIVERS] = { [XEN_UNIFIED_HYPERVISOR_OFFSET] = &xenHypervisorDriver, @@ -64,6 +67,62 @@ xenUnifiedError (virConnectPtr conn, virErrorNumber error, const char *info) errmsg, info, NULL, 0, 0, errmsg, info); } +/* + * Helper functions currently used in the NUMA code + * Those variables should not be accessed directly but through helper + * functions xenNbCells() and xenNbCpu() available to all Xen backends + */ +static int nbNodeCells = -1; +static int nbNodeCpus = -1; + +/** + * xenNumaInit: + * @conn: pointer to the hypervisor connection + * + * Initializer for previous variables. We currently assume that + * the number of physical CPU and the numebr of NUMA cell is fixed + * until reboot which might be false in future Xen implementations. + */ +static void +xenNumaInit(virConnectPtr conn) { + virNodeInfo nodeInfo; + int ret; + + ret = xenUnifiedNodeGetInfo(conn, &nodeInfo); + if (ret < 0) + return; + nbNodeCells = nodeInfo.nodes; + nbNodeCpus = nodeInfo.cpus; +} + +/** + * xenNbCells: + * @conn: pointer to the hypervisor connection + * + * Number of NUMa cells present in the actual Node + * + * Returns the number of NUMA cells available on that Node + */ +int xenNbCells(virConnectPtr conn) { + if (nbNodeCells < 0) + xenNumaInit(conn); + return(nbNodeCells); +} + +/** + * xenNbCpus: + * @conn: pointer to the hypervisor connection + * + * Number of NUMa cells present in the actual Node + * + * Returns the number of NUMA cells available on that Node + */ +int xenNbCpus(virConnectPtr conn) { + if (nbNodeCpus < 0) + xenNumaInit(conn); + return(nbNodeCpus); +} + /*----- Dispatch functions. -----*/ /* These dispatch functions follow the model used historically diff --git a/src/xen_unified.h b/src/xen_unified.h index 0d991bff345f54794be26a8204517f83c01961fe..86cc1c0ba5d726f2fb8b41e89ad4d83945bb22ee 100644 --- a/src/xen_unified.h +++ b/src/xen_unified.h @@ -116,6 +116,9 @@ struct _xenUnifiedPrivate { typedef struct _xenUnifiedPrivate *xenUnifiedPrivatePtr; + +int xenNbCells(virConnectPtr conn); +int xenNbCpus(virConnectPtr conn); #ifdef __cplusplus } #endif diff --git a/src/xend_internal.c b/src/xend_internal.c index 142835fc4d9707913a87a1ac75f0f22d077c38ec..e407a48805246dbef657c058d4cd8c14b40c2ef9 100644 --- a/src/xend_internal.c +++ b/src/xend_internal.c @@ -1895,352 +1895,6 @@ sexpr_to_xend_node_info(struct sexpr *root, virNodeInfoPtr info) return (0); } -/** - * skipSpaces: - * @str: pointer to the char pointer used - * - * Skip potential blanks, this includes space tabs, line feed, - * carriage returns and also '\\' which can be erronously emitted - * by xend - */ -static void -skipSpaces(const char **str) { - const char *cur = *str; - - while ((*cur == ' ') || (*cur == '\t') || (*cur == '\n') || - (*cur == '\r') || (*cur == '\\')) cur++; - *str = cur; -} - -/** - * parseNumber: - * @str: pointer to the char pointer used - * - * Parse a number - * - * Returns the CPU number or -1 in case of error. @str will be - * updated to skip the number. - */ -static int -parseNumber(const char **str) { - int ret = 0; - const char *cur = *str; - - if ((*cur < '0') || (*cur > '9')) - return(-1); - - while ((*cur >= '0') && (*cur <= '9')) { - ret = ret * 10 + (*cur - '0'); - cur++; - } - *str = cur; - return(ret); -} - -/** - * parseCpuNumber: - * @str: pointer to the char pointer used - * @maxcpu: maximum CPU number allowed - * - * Parse a CPU number - * - * Returns the CPU number or -1 in case of error. @str will be - * updated to skip the number. - */ -static int -parseCpuNumber(const char **str, int maxcpu) { - int ret = 0; - const char *cur = *str; - - if ((*cur < '0') || (*cur > '9')) - return(-1); - - while ((*cur >= '0') && (*cur <= '9')) { - ret = ret * 10 + (*cur - '0'); - if (ret > maxcpu) - return(-1); - cur++; - } - *str = cur; - return(ret); -} - -#if 0 /* Not used yet */ -/** - * saveCpuSet: - * @conn: connection - * @cpuset: pointer to a char array for the CPU set - * @maxcpu: number of elements available in @cpuset - * - * Serialize the cpuset to a string - * - * Returns the new string NULL in case of error. The string need to be - * freed by the caller. - */ -static char * -saveCpuSet(virConnectPtr conn, char *cpuset, int maxcpu) -{ - virBufferPtr buf; - char *ret; - int start, cur; - int first = 1; - - if ((cpuset == NULL) || (maxcpu <= 0) || (maxcpu >100000)) - return(NULL); - - buf = virBufferNew(1000); - if (buf == NULL) { - virXendError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer")); - return(NULL); - } - cur = 0; - start = -1; - while (cur < maxcpu) { - if (cpuset[cur]) { - if (start == -1) - start = cur; - } else if (start != -1) { - if (!first) - virBufferAdd(buf, ",", -1); - else - first = 0; - if (cur == start + 1) - virBufferVSprintf(buf, "%d", start); - else if (cur == start + 2) - virBufferVSprintf(buf, "%d,%d", start, cur - 1); - else - virBufferVSprintf(buf, "%d-%d", start, cur - 1); - start = -1; - } - cur++; - } - if (start != -1) { - if (!first) - virBufferAdd(buf, ",", -1); - if (maxcpu == start + 1) - virBufferVSprintf(buf, "%d", start); - else if (maxcpu == start + 2) - virBufferVSprintf(buf, "%d,%d", start, maxcpu - 1); - else - virBufferVSprintf(buf, "%d-%d", start, maxcpu - 1); - } - ret = virBufferContentAndFree(buf); - return(ret); -} -#endif - -/** - * parseCpuSet: - * @str: pointer to a CPU set string pointer - * @sep: potential character used to mark the end of string if not 0 - * @cpuset: pointer to a char array for the CPU set - * @maxcpu: number of elements available in @cpuset - * - * Parse the cpu set, it will set the value for enabled CPUs in the @cpuset - * to 1, and 0 otherwise. The syntax allows coma separated entries each - * can be either a CPU number, ^N to unset that CPU or N-M for ranges. - * - * Returns the number of CPU found in that set, or -1 in case of error. - * @cpuset is modified accordingly to the value parsed. - * @str is updated to the end of the part parsed - */ -static int -parseCpuSet(virConnectPtr conn, const char **str, char sep, char *cpuset, - int maxcpu) -{ - const char *cur; - int ret = 0; - int i, start, last; - int neg = 0; - - if ((str == NULL) || (cpuset == NULL) || (maxcpu <= 0) || (maxcpu >100000)) - return(-1); - - cur = *str; - skipSpaces(&cur); - if (*cur == 0) - goto parse_error; - - /* initialize cpumap to all 0s */ - for (i = 0;i < maxcpu;i++) - cpuset[i] = 0; - ret = 0; - - while ((*cur != 0) && (*cur != sep)) { - /* - * 3 constructs are allowed: - * - N : a single CPU number - * - N-M : a range of CPU numbers with N < M - * - ^N : remove a single CPU number from the current set - */ - if (*cur == '^') { - cur++; - neg = 1; - } - - if ((*cur < '0') || (*cur > '9')) - goto parse_error; - start = parseCpuNumber(&cur, maxcpu); - if (start < 0) - goto parse_error; - skipSpaces(&cur); - if ((*cur == ',') || (*cur == 0) || (*cur == sep)) { - if (neg) { - if (cpuset[start] == 1) { - cpuset[start] = 0; - ret--; - } - } else { - if (cpuset[start] == 0) { - cpuset[start] = 1; - ret++; - } - } - } else if (*cur == '-') { - if (neg) - goto parse_error; - cur++; - skipSpaces(&cur); - last = parseCpuNumber(&cur, maxcpu); - if (last < start) - goto parse_error; - for (i = start;i <= last;i++) { - if (cpuset[i] == 0) { - cpuset[i] = 1; - ret++; - } - } - skipSpaces(&cur); - } - if (*cur == ',') { - cur++; - skipSpaces(&cur); - neg = 0; - } else if ((*cur == 0) || (*cur == sep)) { - break; - } else - goto parse_error; - } - *str = cur; - return(ret); - -parse_error: - virXendError(conn, VIR_ERR_XEN_CALL, - _("topology cpuset syntax error")); - return(-1); -} - - -/** - * parseXenCpuTopology: - * @xml: XML output buffer - * @str: the topology string - * @maxcpu: number of elements available in @cpuset - * - * Parse a Xend CPU topology string and build the associated XML - * format. - * - * Returns 0 in case of success, -1 in case of error - */ -static int -parseTopology(virConnectPtr conn, virBufferPtr xml, const char *str, - int maxcpu) -{ - const char *cur; - char *cpuset = NULL; - int cell, cpu, nb_cpus; - int ret; - - if ((str == NULL) || (xml == NULL) || (maxcpu <= 0) || (maxcpu >100000)) - return(-1); - - cpuset = malloc(maxcpu * sizeof(char)); - if (cpuset == NULL) - goto memory_error; - - cur = str; - while (*cur != 0) { - /* - * Find the next NUMA cell described in the xend output - */ - cur = strstr(cur, "node"); - if (cur == NULL) - break; - cur += 4; - cell = parseNumber(&cur); - if (cell < 0) - goto parse_error; - skipSpaces(&cur); - if (*cur != ':') - goto parse_error; - cur++; - skipSpaces(&cur); - if (!strncmp (cur, "no cpus", 7)) { - nb_cpus = 0; - for (cpu = 0;cpu < maxcpu;cpu++) - cpuset[cpu] = 0; - } else { - nb_cpus = parseCpuSet(conn, &cur, 'n', cpuset, maxcpu); - if (nb_cpus < 0) - goto error; - } - - /* - * add xml for all cpus associated with that cell - */ - ret = virBufferVSprintf (xml, "\ - \n\ - \n", cell, nb_cpus); -#ifdef STANDALONE - { - char *dump; - - dump = saveCpuSet(conn, cpuset, maxcpu); - if (dump != NULL) { - virBufferVSprintf (xml, " %s\n", dump); - free(dump); - } else { - virBufferVSprintf (xml, " %s\n", - "Failed to dump CPU set"); - } - } -#endif - if (ret < 0) - goto memory_error; - for (cpu = 0;cpu < maxcpu;cpu++) { - if (cpuset[cpu] == 1) { - ret = virBufferVSprintf (xml, "\ - \n", cpu); - if (ret < 0) - goto memory_error; - } - } - ret = virBufferAdd (xml, "\ - \n\ - \n", -1); - if (ret < 0) - goto memory_error; - - } - free(cpuset); - return(0); - -parse_error: - virXendError(conn, VIR_ERR_XEN_CALL, - _("topology syntax error")); -error: - if (cpuset != NULL) - free(cpuset); - - return(-1); - -memory_error: - if (cpuset != NULL) - free(cpuset); - virXendError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer")); - return(-1); -} - /** * sexpr_to_xend_topology_xml: * @root: an S-Expression describing a node @@ -2276,7 +1930,7 @@ sexpr_to_xend_topology_xml(virConnectPtr conn, struct sexpr *root, virBufferPtr numCells); if (r < 0) goto vir_buffer_failed; - r = parseTopology(conn, xml, nodeToCpu, numCpus); + r = virParseXenCpuTopology(conn, xml, nodeToCpu, numCpus); if (r < 0) goto error; r = virBufferAdd (xml, "\ diff --git a/src/xml.c b/src/xml.c index aa1884516718870a07a8f508801c2e0d016f1bc8..f85e50446efe36477a4bf9c3132f9995a2f02f49 100644 --- a/src/xml.c +++ b/src/xml.c @@ -24,6 +24,7 @@ #include "xml.h" #include "buf.h" #include "xs_internal.h" /* for xenStoreDomainGetNetworkID */ +#include "xen_unified.h" #ifndef PROXY /** @@ -48,6 +49,362 @@ virXMLError(virConnectPtr conn, virErrorNumber error, const char *info, int valu errmsg, info, NULL, value, 0, errmsg, info, value); } +/************************************************************************ + * * + * Parser and converter for the CPUset strings used in libvirt * + * * + ************************************************************************/ + +/** + * skipSpaces: + * @str: pointer to the char pointer used + * + * Skip potential blanks, this includes space tabs, line feed, + * carriage returns and also '\\' which can be erronously emitted + * by xend + */ +static void +skipSpaces(const char **str) { + const char *cur = *str; + + while ((*cur == ' ') || (*cur == '\t') || (*cur == '\n') || + (*cur == '\r') || (*cur == '\\')) cur++; + *str = cur; +} + +/** + * parseNumber: + * @str: pointer to the char pointer used + * + * Parse a number + * + * Returns the CPU number or -1 in case of error. @str will be + * updated to skip the number. + */ +static int +parseNumber(const char **str) { + int ret = 0; + const char *cur = *str; + + if ((*cur < '0') || (*cur > '9')) + return(-1); + + while ((*cur >= '0') && (*cur <= '9')) { + ret = ret * 10 + (*cur - '0'); + cur++; + } + *str = cur; + return(ret); +} + +/** + * parseCpuNumber: + * @str: pointer to the char pointer used + * @maxcpu: maximum CPU number allowed + * + * Parse a CPU number + * + * Returns the CPU number or -1 in case of error. @str will be + * updated to skip the number. + */ +static int +parseCpuNumber(const char **str, int maxcpu) { + int ret = 0; + const char *cur = *str; + + if ((*cur < '0') || (*cur > '9')) + return(-1); + + while ((*cur >= '0') && (*cur <= '9')) { + ret = ret * 10 + (*cur - '0'); + if (ret > maxcpu) + return(-1); + cur++; + } + *str = cur; + return(ret); +} + +/** + * saveCpuSet: + * @conn: connection + * @cpuset: pointer to a char array for the CPU set + * @maxcpu: number of elements available in @cpuset + * + * Serialize the cpuset to a string + * + * Returns the new string NULL in case of error. The string need to be + * freed by the caller. + */ +static char * +saveCpuSet(virConnectPtr conn, char *cpuset, int maxcpu) +{ + virBufferPtr buf; + char *ret; + int start, cur; + int first = 1; + + if ((cpuset == NULL) || (maxcpu <= 0) || (maxcpu >100000)) + return(NULL); + + buf = virBufferNew(1000); + if (buf == NULL) { + virXMLError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer"), 1000); + return(NULL); + } + cur = 0; + start = -1; + while (cur < maxcpu) { + if (cpuset[cur]) { + if (start == -1) + start = cur; + } else if (start != -1) { + if (!first) + virBufferAdd(buf, ",", -1); + else + first = 0; + if (cur == start + 1) + virBufferVSprintf(buf, "%d", start); + else if (cur == start + 2) + virBufferVSprintf(buf, "%d,%d", start, cur - 1); + else + virBufferVSprintf(buf, "%d-%d", start, cur - 1); + start = -1; + } + cur++; + } + if (start != -1) { + if (!first) + virBufferAdd(buf, ",", -1); + if (maxcpu == start + 1) + virBufferVSprintf(buf, "%d", start); + else if (maxcpu == start + 2) + virBufferVSprintf(buf, "%d,%d", start, maxcpu - 1); + else + virBufferVSprintf(buf, "%d-%d", start, maxcpu - 1); + } + ret = virBufferContentAndFree(buf); + return(ret); +} + +/** + * virParseCpuSet: + * @str: pointer to a CPU set string pointer + * @sep: potential character used to mark the end of string if not 0 + * @cpuset: pointer to a char array for the CPU set + * @maxcpu: number of elements available in @cpuset + * + * Parse the cpu set, it will set the value for enabled CPUs in the @cpuset + * to 1, and 0 otherwise. The syntax allows coma separated entries each + * can be either a CPU number, ^N to unset that CPU or N-M for ranges. + * + * Returns the number of CPU found in that set, or -1 in case of error. + * @cpuset is modified accordingly to the value parsed. + * @str is updated to the end of the part parsed + */ +int +virParseCpuSet(virConnectPtr conn, const char **str, char sep, char *cpuset, + int maxcpu) +{ + const char *cur; + int ret = 0; + int i, start, last; + int neg = 0; + + if ((str == NULL) || (cpuset == NULL) || (maxcpu <= 0) || (maxcpu >100000)) + return(-1); + + cur = *str; + skipSpaces(&cur); + if (*cur == 0) + goto parse_error; + + /* initialize cpumap to all 0s */ + for (i = 0;i < maxcpu;i++) + cpuset[i] = 0; + ret = 0; + + while ((*cur != 0) && (*cur != sep)) { + /* + * 3 constructs are allowed: + * - N : a single CPU number + * - N-M : a range of CPU numbers with N < M + * - ^N : remove a single CPU number from the current set + */ + if (*cur == '^') { + cur++; + neg = 1; + } + + if ((*cur < '0') || (*cur > '9')) + goto parse_error; + start = parseCpuNumber(&cur, maxcpu); + if (start < 0) + goto parse_error; + skipSpaces(&cur); + if ((*cur == ',') || (*cur == 0) || (*cur == sep)) { + if (neg) { + if (cpuset[start] == 1) { + cpuset[start] = 0; + ret--; + } + } else { + if (cpuset[start] == 0) { + cpuset[start] = 1; + ret++; + } + } + } else if (*cur == '-') { + if (neg) + goto parse_error; + cur++; + skipSpaces(&cur); + last = parseCpuNumber(&cur, maxcpu); + if (last < start) + goto parse_error; + for (i = start;i <= last;i++) { + if (cpuset[i] == 0) { + cpuset[i] = 1; + ret++; + } + } + skipSpaces(&cur); + } + if (*cur == ',') { + cur++; + skipSpaces(&cur); + neg = 0; + } else if ((*cur == 0) || (*cur == sep)) { + break; + } else + goto parse_error; + } + *str = cur; + return(ret); + +parse_error: + virXMLError(conn, VIR_ERR_XEN_CALL, + _("topology cpuset syntax error"), 0); + return(-1); +} + +/** + * virParseXenCpuTopology: + * @xml: XML output buffer + * @str: the topology string + * @maxcpu: number of elements available in @cpuset + * + * Parse a Xend CPU topology string and build the associated XML + * format. + * + * Returns 0 in case of success, -1 in case of error + */ +int +virParseXenCpuTopology(virConnectPtr conn, virBufferPtr xml, const char *str, + int maxcpu) +{ + const char *cur; + char *cpuset = NULL; + int cell, cpu, nb_cpus; + int ret; + + if ((str == NULL) || (xml == NULL) || (maxcpu <= 0) || (maxcpu >100000)) + return(-1); + + cpuset = malloc(maxcpu * sizeof(char)); + if (cpuset == NULL) + goto memory_error; + + cur = str; + while (*cur != 0) { + /* + * Find the next NUMA cell described in the xend output + */ + cur = strstr(cur, "node"); + if (cur == NULL) + break; + cur += 4; + cell = parseNumber(&cur); + if (cell < 0) + goto parse_error; + skipSpaces(&cur); + if (*cur != ':') + goto parse_error; + cur++; + skipSpaces(&cur); + if (!strncmp (cur, "no cpus", 7)) { + nb_cpus = 0; + for (cpu = 0;cpu < maxcpu;cpu++) + cpuset[cpu] = 0; + } else { + nb_cpus = virParseCpuSet(conn, &cur, 'n', cpuset, maxcpu); + if (nb_cpus < 0) + goto error; + } + + /* + * add xml for all cpus associated with that cell + */ + ret = virBufferVSprintf (xml, "\ + \n\ + \n", cell, nb_cpus); +#ifdef STANDALONE + { + char *dump; + + dump = saveCpuSet(conn, cpuset, maxcpu); + if (dump != NULL) { + virBufferVSprintf (xml, " %s\n", dump); + free(dump); + } else { + virBufferVSprintf (xml, " %s\n", + "Failed to dump CPU set"); + } + } +#endif + if (ret < 0) + goto memory_error; + for (cpu = 0;cpu < maxcpu;cpu++) { + if (cpuset[cpu] == 1) { + ret = virBufferVSprintf (xml, "\ + \n", cpu); + if (ret < 0) + goto memory_error; + } + } + ret = virBufferAdd (xml, "\ + \n\ + \n", -1); + if (ret < 0) + goto memory_error; + + } + free(cpuset); + return(0); + +parse_error: + virXMLError(conn, VIR_ERR_XEN_CALL, + _("topology syntax error"), 0); +error: + if (cpuset != NULL) + free(cpuset); + + return(-1); + +memory_error: + if (cpuset != NULL) + free(cpuset); + virXMLError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer"), 0); + return(-1); +} + + +/************************************************************************ + * * + * Wrappers around libxml2 XPath specific functions * + * * + ************************************************************************/ + /** * virXPathString: * @xpath: the XPath string to evaluate @@ -271,6 +628,12 @@ virXPathNodeSet(const char *xpath, xmlXPathContextPtr ctxt, xmlNodePtr **list) { return(ret); } +/************************************************************************ + * * + * Converter functions to go from the XML tree to an S-Expr for Xen * + * * + ************************************************************************/ + /** * virtDomainParseXMLGraphicsDescImage: * @conn: pointer to the hypervisor connection @@ -1167,6 +1530,36 @@ virDomainParseXMLDesc(virConnectPtr conn, const char *xmldesc, char **name, int } virBufferVSprintf(&buf, "(vcpus %u)", vcpus); + str = virXPathString("string(/domain/vcpu/@cpuset)", ctxt); + if (str != NULL) { + int maxcpu = xenNbCpus(conn); + char *cpuset = NULL; + char *ranges = NULL; + const char *cur = str; + + /* + * Parse the CPUset attribute given in libvirt format and reserialize + * it in a range format guaranteed to be understood by Xen. + */ + if (maxcpu > 0) { + cpuset = malloc(maxcpu * sizeof(char)); + if (cpuset != NULL) { + res = virParseCpuSet(conn, &cur, 0, cpuset, maxcpu); + if (res > 0) { + ranges = saveCpuSet(conn, cpuset, maxcpu); + if (ranges != NULL) { + virBufferVSprintf(&buf, "(cpus '%s')", ranges); + free(ranges); + } + } + free(cpuset); + } else { + virXMLError(conn, VIR_ERR_NO_MEMORY, xmldesc, 0); + } + } + free(str); + } + str = virXPathString("string(/domain/uuid[1])", ctxt); if (str != NULL) { virBufferVSprintf(&buf, "(uuid '%s')", str); diff --git a/src/xml.h b/src/xml.h index c572d6826f3eefc0e368e48fdb3fc3f6a39efe5b..ff355ee94be5fa4e727eab988c19d52c032203f6 100644 --- a/src/xml.h +++ b/src/xml.h @@ -7,6 +7,7 @@ #include "libvirt/libvirt.h" #include "internal.h" +#include "buf.h" #include #include @@ -31,9 +32,28 @@ int virXPathNodeSet (const char *xpath, xmlXPathContextPtr ctxt, xmlNodePtr **list); -char *virDomainParseXMLDesc(virConnectPtr conn, const char *xmldesc, char **name, int xendConfigVersion); -char *virParseXMLDevice(virConnectPtr conn, const char *xmldesc, int hvm, int xendConfigVersion); - int virDomainXMLDevID(virDomainPtr domain, const char *xmldesc, char *class, char *ref, int ref_len); +int virParseXenCpuTopology(virConnectPtr conn, + virBufferPtr xml, + const char *str, + int maxcpu); +int virParseCpuSet (virConnectPtr conn, + const char **str, + char sep, + char *cpuset, + int maxcpu); +char * virDomainParseXMLDesc(virConnectPtr conn, + const char *xmldesc, + char **name, + int xendConfigVersion); +char * virParseXMLDevice(virConnectPtr conn, + const char *xmldesc, + int hvm, + int xendConfigVersion); +int virDomainXMLDevID(virDomainPtr domain, + const char *xmldesc, + char *class, + char *ref, + int ref_len); #ifdef __cplusplus }