]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
* docs/format.html docs/libvir.html: documentation cleaups
authorDaniel Veillard <veillard@redhat.com>
Mon, 22 Oct 2007 20:28:55 +0000 (20:28 +0000)
committerDaniel Veillard <veillard@redhat.com>
Mon, 22 Oct 2007 20:28:55 +0000 (20:28 +0000)
  from Jim Paris
Daniel

ChangeLog
docs/format.html
docs/libvir.html
src/xen_internal.c
src/xen_unified.c
src/xen_unified.h
src/xend_internal.c
src/xml.c
src/xml.h

index af02d845da8cd5ba25da560e7e5df6a3e4aea4c5..ef87988482131946720f6d007260c23d5a5d6204 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Mon Oct 22 22:27:40 CEST 2007 Daniel Veillard <veillard@redhat.com>
+
+       * docs/format.html docs/libvir.html: documentation cleaups
+         from Jim Paris
+
 Mon Oct 22 15:05:30 CEST 2007 Daniel Veillard <veillard@redhat.com>
 
        * src/xend_internal.c: update to cpuset parsing code for NUMA
index efdbcde19457fff5e2550fd74754c11c3aab1d94..26a4c3d9c81cfc1b84f56ad6eaf00b5d690ed206 100644 (file)
@@ -230,7 +230,7 @@ support a variety of options:</p><ol><li>Userspace SLIRP stack
     <pre>&lt;interface type='user'/&gt;</pre>
     <pre>
 &lt;interface type='user'&gt;                                                  
-  &lt;mac address="11:22:33:44:55:66:/&gt;                                     
+  &lt;mac address="11:22:33:44:55:66"/&gt;                                     
 &lt;/interface&gt;
     </pre>
   </li>
@@ -253,7 +253,7 @@ support a variety of options:</p><ol><li>Userspace SLIRP stack
 &lt;interface type='network'&gt;
   &lt;source network='default'/&gt;
   &lt;target dev='vnet7'/&gt;
-  &lt;mac address="11:22:33:44:55:66:/&gt;
+  &lt;mac address="11:22:33:44:55:66"/&gt;
 &lt;/interface&gt;
     </pre>
   </li>
@@ -273,12 +273,8 @@ support a variety of options:</p><ol><li>Userspace SLIRP stack
 &lt;interface type='bridge'&gt;
   &lt;source dev='br0'/&gt;
   &lt;target dev='vnet7'/&gt;
-  &lt;mac address="11:22:33:44:55:66:/&gt;
-&lt;/interface&gt;       &lt;interface type='bridge'&gt;
-         &lt;source dev='br0'/&gt;
-         &lt;target dev='vnet7'/&gt;
-         &lt;mac address="11:22:33:44:55:66:/&gt;
-       &lt;/interface&gt;</pre>
+  &lt;mac address="11:22:33:44:55:66"/&gt;
+&lt;/interface&gt;</pre> 
   </li>
   <li>Generic connection to LAN
     <p>Provides a means for the administrator to execute an arbitrary script
index 22bb1681a22a425e16fcd9a63fe313a74058f11d..571b9c1c33d722f5bf96642b1953e7f438dd6aca 100644 (file)
@@ -964,7 +964,7 @@ support a variety of options:</p>
     <pre>&lt;interface type='user'/&gt;</pre>
     <pre>
 &lt;interface type='user'&gt;                                                  
-  &lt;mac address="11:22:33:44:55:66:/&gt;                                     
+  &lt;mac address="11:22:33:44:55:66"/&gt;                                     
 &lt;/interface&gt;
     </pre>
   </li>
@@ -987,7 +987,7 @@ support a variety of options:</p>
 &lt;interface type='network'&gt;
   &lt;source network='default'/&gt;
   &lt;target dev='vnet7'/&gt;
-  &lt;mac address="11:22:33:44:55:66:/&gt;
+  &lt;mac address="11:22:33:44:55:66"/&gt;
 &lt;/interface&gt;
     </pre>
   </li>
@@ -1007,12 +1007,8 @@ support a variety of options:</p>
 &lt;interface type='bridge'&gt;
   &lt;source dev='br0'/&gt;
   &lt;target dev='vnet7'/&gt;
-  &lt;mac address="11:22:33:44:55:66:/&gt;
-&lt;/interface&gt;       &lt;interface type='bridge'&gt;
-         &lt;source dev='br0'/&gt;
-         &lt;target dev='vnet7'/&gt;
-         &lt;mac address="11:22:33:44:55:66:/&gt;
-       &lt;/interface&gt;</pre>
+  &lt;mac address="11:22:33:44:55:66"/&gt;
+&lt;/interface&gt;</pre> 
   </li>
   <li>Generic connection to LAN
     <p>Provides a means for the administrator to execute an arbitrary script
index 8cc5a5cf805f39613178457805e795f8b7861c7e..0bc956e335ad781cf52178374624c5347e7932fd 100644 (file)
@@ -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
      */
index b5c27e443c49627ef58711b1997bb50caf593763..760ec5282f84c7d78c297feb22e6933a3006bc25 100644 (file)
@@ -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
index 0d991bff345f54794be26a8204517f83c01961fe..86cc1c0ba5d726f2fb8b41e89ad4d83945bb22ee 100644 (file)
@@ -116,6 +116,9 @@ struct _xenUnifiedPrivate {
 
 typedef struct _xenUnifiedPrivate *xenUnifiedPrivatePtr;
 
+
+int xenNbCells(virConnectPtr conn);
+int xenNbCpus(virConnectPtr conn);
 #ifdef __cplusplus
 }
 #endif
index 142835fc4d9707913a87a1ac75f0f22d077c38ec..e407a48805246dbef657c058d4cd8c14b40c2ef9 100644 (file)
@@ -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, "\
-      <cell id='%d'>\n\
-        <cpus num='%d'>\n", cell, nb_cpus);
-#ifdef STANDALONE
-        {
-           char *dump;
-
-           dump = saveCpuSet(conn, cpuset, maxcpu);
-           if (dump != NULL) {
-               virBufferVSprintf (xml, "           <dump>%s</dump>\n", dump);
-               free(dump);
-           } else {
-               virBufferVSprintf (xml, "           <error>%s</error>\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, "\
-           <cpu id='%d'/>\n", cpu);
-               if (ret < 0)
-                   goto memory_error;
-           }
-       }
-       ret = virBufferAdd (xml, "\
-        </cpus>\n\
-      </cell>\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, "\
index aa1884516718870a07a8f508801c2e0d016f1bc8..f85e50446efe36477a4bf9c3132f9995a2f02f49 100644 (file)
--- 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, "\
+      <cell id='%d'>\n\
+        <cpus num='%d'>\n", cell, nb_cpus);
+#ifdef STANDALONE
+        {
+           char *dump;
+
+           dump = saveCpuSet(conn, cpuset, maxcpu);
+           if (dump != NULL) {
+               virBufferVSprintf (xml, "           <dump>%s</dump>\n", dump);
+               free(dump);
+           } else {
+               virBufferVSprintf (xml, "           <error>%s</error>\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, "\
+           <cpu id='%d'/>\n", cpu);
+               if (ret < 0)
+                   goto memory_error;
+           }
+       }
+       ret = virBufferAdd (xml, "\
+        </cpus>\n\
+      </cell>\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);
index c572d6826f3eefc0e368e48fdb3fc3f6a39efe5b..ff355ee94be5fa4e727eab988c19d52c032203f6 100644 (file)
--- a/src/xml.h
+++ b/src/xml.h
@@ -7,6 +7,7 @@
 
 #include "libvirt/libvirt.h"
 #include "internal.h"
+#include "buf.h"
 
 #include <libxml/parser.h>
 #include <libxml/tree.h>
@@ -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
 }