Index: src/Makefile.am =================================================================== RCS file: /data/cvs/libvirt/src/Makefile.am,v retrieving revision 1.46 diff -u -p -u -p -r1.46 Makefile.am --- src/Makefile.am 19 Jul 2007 16:22:40 -0000 1.46 +++ src/Makefile.am 25 Jul 2007 14:28:12 -0000 @@ -50,6 +50,7 @@ CLIENT_SOURCES = \ qemu_conf.c qemu_conf.h \ openvz_conf.c openvz_conf.h \ openvz_driver.c openvz_driver.h \ + nodeinfo.h nodeinfo.c \ util.c util.h SERVER_SOURCES = \ Index: src/internal.h =================================================================== RCS file: /data/cvs/libvirt/src/internal.h,v retrieving revision 1.46 diff -u -p -u -p -r1.46 internal.h --- src/internal.h 6 Jul 2007 15:02:09 -0000 1.46 +++ src/internal.h 25 Jul 2007 14:28:12 -0000 @@ -36,6 +36,8 @@ extern "C" { #define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0) #define STRNEQ(a,b) (strcmp((a),(b)) != 0) #define STRCASENEQ(a,b) (strcasecmp((a),(b)) != 0) +#define STREQLEN(a,b,n) (strncmp((a),(b),(n)) == 0) +#define STRNEQLEN(a,b,n) (strncmp((a),(b),(n)) != 0) /** * ATTRIBUTE_UNUSED: Index: src/nodeinfo.c =================================================================== RCS file: src/nodeinfo.c diff -N src/nodeinfo.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/nodeinfo.c 25 Jul 2007 14:28:12 -0000 @@ -0,0 +1,193 @@ +/* + * nodeinfo.c: Helper routines for OS specific node information + * + * Copyright (C) 2006, 2007 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange + */ + +#include +#include +#include +#include +#include +#include + +#include "nodeinfo.h" + +#ifdef __linux__ +#define MEMINFO_PATH "/proc/meminfo" +#define CPUINFO_PATH "/proc/cpuinfo" + +/* NB, these are not static as we need to call them from testsuite */ +int linuxNodeInfoCPUPopulate(virConnectPtr conn, FILE *cpuinfo, virNodeInfoPtr nodeinfo); +int linuxNodeInfoMemPopulate(virConnectPtr conn, FILE *meminfo, virNodeInfoPtr nodeinfo); + +int linuxNodeInfoCPUPopulate(virConnectPtr conn, FILE *cpuinfo, virNodeInfoPtr nodeinfo) { + char line[1024]; + + nodeinfo->cpus = 0; + nodeinfo->mhz = 0; + nodeinfo->nodes = nodeinfo->sockets = nodeinfo->cores = nodeinfo->threads = 1; + + /* NB: It is impossible to fill our nodes, since cpuinfo + * has not knowledge of NUMA nodes */ + + /* XXX hyperthreads */ + while (fgets(line, sizeof(line), cpuinfo) != NULL) { + char *buf = line; + if (STREQLEN(buf, "processor", 9)) { /* aka a single logical CPU */ + buf += 9; + while (*buf && isspace(*buf)) + buf++; + if (*buf != ':') { + __virRaiseError(conn, NULL, NULL, 0, VIR_ERR_INTERNAL_ERROR, + VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, + "parsing cpuinfo processor"); + return -1; + } + nodeinfo->cpus++; + } else if (STREQLEN(buf, "cpu MHz", 7)) { + buf += 9; + while (*buf && isspace(*buf)) + buf++; + if (*buf != ':' || !buf[1]) { + __virRaiseError(conn, NULL, NULL, 0, VIR_ERR_INTERNAL_ERROR, + VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, + "parsing cpuinfo cpu MHz"); + return -1; + } + nodeinfo->mhz = (unsigned int)strtol(buf+1, NULL, 10); + } else if (STREQLEN(buf, "cpu cores", 9)) { /* aka cores */ + unsigned int id; + buf += 9; + while (*buf && isspace(*buf)) + buf++; + if (*buf != ':' || !buf[1]) { + __virRaiseError(conn, NULL, NULL, 0, VIR_ERR_INTERNAL_ERROR, + VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, + "parsing cpuinfo cpu cores %c", *buf); + return -1; + } + id = (unsigned int)strtol(buf+1, NULL, 10); + if (id > nodeinfo->cores) + nodeinfo->cores = id; + } + } + + if (!nodeinfo->cpus) { + __virRaiseError(conn, NULL, NULL, 0, VIR_ERR_INTERNAL_ERROR, + VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, + "no cpus found"); + return -1; + } + + /* + * Can't reliably count sockets from proc metadata, so + * infer it based on total CPUs vs cores. + * XXX hyperthreads + */ + nodeinfo->sockets = nodeinfo->cpus / nodeinfo->cores; + + return 0; +} + + +int linuxNodeInfoMemPopulate(virConnectPtr conn, FILE *meminfo, virNodeInfoPtr nodeinfo) { + char line[1024]; + + nodeinfo->memory = 0; + + while (fgets(line, sizeof(line), meminfo) != NULL) { + if (STREQLEN(line, "MemTotal:", 9)) { + nodeinfo->memory = (unsigned int)strtol(line + 10, NULL, 10); + } + } + if (!nodeinfo->memory) { + __virRaiseError(conn, NULL, NULL, 0, VIR_ERR_INTERNAL_ERROR, + VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, + "no memory found"); + return -1; + } + + return 0; +} + + +#endif + +int virNodeInfoPopulate(virConnectPtr conn, + virNodeInfoPtr nodeinfo) { + struct utsname info; +#ifdef __linux__ + int ret; + FILE *cpuinfo, *meminfo; +#endif + + if (uname(&info) < 0) { + __virRaiseError(conn, NULL, NULL, 0, VIR_ERR_INTERNAL_ERROR, + VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, + "cannot extract machine type %s", strerror(errno)); + return -1; + } + + strncpy(nodeinfo->model, info.machine, sizeof(nodeinfo->model)-1); + nodeinfo->model[sizeof(nodeinfo->model)-1] = '\0'; + +#ifdef __linux__ + cpuinfo = fopen(CPUINFO_PATH, "r"); + if (!cpuinfo) { + __virRaiseError(conn, NULL, NULL, 0, VIR_ERR_INTERNAL_ERROR, + VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, + "cannot open %s %s", CPUINFO_PATH, strerror(errno)); + return -1; + } + ret = linuxNodeInfoCPUPopulate(conn, cpuinfo, nodeinfo); + fclose(cpuinfo); + if (ret < 0) + return -1; + + meminfo = fopen(MEMINFO_PATH, "r"); + if (!meminfo) { + __virRaiseError(conn, NULL, NULL, 0, VIR_ERR_INTERNAL_ERROR, + VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, + "cannot open %s %s", MEMINFO_PATH, strerror(errno)); + return -1; + } + ret = linuxNodeInfoMemPopulate(conn, meminfo, nodeinfo); + fclose(meminfo); + + return ret; +#else + /* XXX Solaris will need an impl later if they port QEMU driver */ + __virRaiseError(conn, NULL, NULL, 0, VIR_ERR_INTERNAL_ERROR, + VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, + "%s:%s not implemented on this platform\n", __FILE__, __FUNCTION__); + return -1; +#endif +} + + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ Index: src/nodeinfo.h =================================================================== RCS file: src/nodeinfo.h diff -N src/nodeinfo.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/nodeinfo.h 25 Jul 2007 14:28:12 -0000 @@ -0,0 +1,39 @@ +/* + * nodeinfo.c: Helper routines for OS specific node information + * + * Copyright (C) 2006, 2007 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange + */ + +#ifndef __VIR_NODEINFO_H__ +#define __VIR_NODEINFO_H__ + +#include "internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + + int virNodeInfoPopulate(virConnectPtr conn, virNodeInfoPtr nodeinfo); + +#ifdef __cplusplus +} +#endif + +#endif /* __VIR_NODEINFO_H__*/ Index: src/openvz_driver.c =================================================================== RCS file: /data/cvs/libvirt/src/openvz_driver.c,v retrieving revision 1.2 diff -u -p -u -p -r1.2 openvz_driver.c --- src/openvz_driver.c 19 Jul 2007 16:22:40 -0000 1.2 +++ src/openvz_driver.c 25 Jul 2007 14:28:12 -0000 @@ -55,12 +55,14 @@ #include "util.h" #include "openvz_driver.h" #include "openvz_conf.h" +#include "nodeinfo.h" #define openvzLog(level, msg...) fprintf(stderr, msg) static virDomainPtr openvzDomainLookupByID(virConnectPtr conn, int id); static char *openvzGetOSType(virDomainPtr dom); +static int openvzGetNodeInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo); static virDomainPtr openvzDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid); static virDomainPtr openvzDomainLookupByName(virConnectPtr conn, const char *name); static int openvzDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info); @@ -327,6 +329,12 @@ static const char *openvzGetType(virConn } +static int openvzGetNodeInfo(virConnectPtr conn, + virNodeInfoPtr nodeinfo) { + return virNodeInfoPopulate(conn, nodeinfo); +} + + static int openvzListDomains(virConnectPtr conn, int *ids, int nids) { int got = 0; int veid, pid, outfd, errfd; @@ -431,7 +439,7 @@ static virDriver openvzDriver = { NULL, /* hostname */ NULL, /* uri */ NULL, /* getMaxVcpus */ - NULL, /* nodeGetInfo */ + openvzGetNodeInfo, /* nodeGetInfo */ NULL, /* getCapabilities */ openvzListDomains, /* listDomains */ openvzNumDomains, /* numOfDomains */ Index: src/qemu_driver.c =================================================================== RCS file: /data/cvs/libvirt/src/qemu_driver.c,v retrieving revision 1.11 diff -u -p -u -p -r1.11 qemu_driver.c --- src/qemu_driver.c 24 Jul 2007 14:24:52 -0000 1.11 +++ src/qemu_driver.c 25 Jul 2007 14:28:12 -0000 @@ -53,6 +53,7 @@ #include "util.h" #include "qemu_driver.h" #include "qemu_conf.h" +#include "nodeinfo.h" static int qemudShutdown(void); @@ -1358,81 +1359,6 @@ static int qemudMonitorCommand(struct qe } -static int qemudGetMemInfo(unsigned long *memory) { - FILE *meminfo = fopen("/proc/meminfo", "r"); - char line[1024]; - - *memory = 0; - - if (!meminfo) { - return -1; - } - - /* XXX NUMA and hyperthreads ? */ - while (fgets(line, sizeof(line), meminfo) != NULL) { - if (!strncmp(line, "MemTotal:", 9)) { - *memory = (unsigned int)strtol(line + 10, NULL, 10); - } - } - fclose(meminfo); - return 0; -} - -static int qemudGetCPUInfo(unsigned int *cpus, unsigned int *mhz, - unsigned int *nodes, unsigned int *sockets, - unsigned int *cores, unsigned int *threads) { - FILE *cpuinfo = fopen("/proc/cpuinfo", "r"); - char line[1024]; - - *cpus = 0; - *mhz = 0; - *nodes = *sockets = *cores = *threads = 1; - - if (!cpuinfo) { - return -1; - } - - /* XXX NUMA and hyperthreads ? */ - while (fgets(line, sizeof(line), cpuinfo) != NULL) { - if (!strncmp(line, "processor\t", 10)) { /* aka a single logical CPU */ - (*cpus)++; - } else if (!strncmp(line, "cpu MHz\t", 8)) { - char *offset = strchr(line, ':'); - if (!offset) - continue; - offset++; - if (!*offset) - continue; - *mhz = (unsigned int)strtol(offset, NULL, 10); - } else if (!strncmp(line, "physical id\t", 12)) { /* aka socket */ - unsigned int id; - char *offset = strchr(line, ':'); - if (!offset) - continue; - offset++; - if (!*offset) - continue; - id = (unsigned int)strtol(offset, NULL, 10); - if ((id+1) > *sockets) - *sockets = (id + 1); - } else if (!strncmp(line, "cpu cores\t", 9)) { /* aka cores */ - unsigned int id; - char *offset = strchr(line, ':'); - if (!offset) - continue; - offset++; - if (!*offset) - continue; - id = (unsigned int)strtol(offset, NULL, 10); - if (id > *cores) - *cores = id; - } - } - fclose(cpuinfo); - - return 0; -} - static virDrvOpenStatus qemudOpen(virConnectPtr conn, const char *name, int flags ATTRIBUTE_UNUSED) { @@ -1485,23 +1411,9 @@ static int qemudGetMaxVCPUs(virConnectPt return -1; } -static int qemudGetNodeInfo(virConnectPtr conn ATTRIBUTE_UNUSED, - virNodeInfoPtr node) { - struct utsname info; - - if (uname(&info) < 0) - return -1; - - strncpy(node->model, info.machine, sizeof(node->model)-1); - node->model[sizeof(node->model)-1] = '\0'; - - if (qemudGetMemInfo(&(node->memory)) < 0) - return -1; - - if (qemudGetCPUInfo(&(node->cpus), &(node->mhz), &(node->nodes), - &(node->sockets), &(node->cores), &(node->threads)) < 0) - return -1; - return 0; +static int qemudGetNodeInfo(virConnectPtr conn, + virNodeInfoPtr nodeinfo) { + return virNodeInfoPopulate(conn, nodeinfo); } static char *qemudGetCapabilities(virConnectPtr conn ATTRIBUTE_UNUSED) { ? tests/nodeinfodata ? tests/nodeinfotest Index: tests/Makefile.am =================================================================== RCS file: /data/cvs/libvirt/tests/Makefile.am,v retrieving revision 1.21 diff -u -p -u -p -r1.21 Makefile.am --- tests/Makefile.am 18 Jul 2007 21:34:22 -0000 1.21 +++ tests/Makefile.am 25 Jul 2007 14:28:21 -0000 @@ -32,10 +32,11 @@ LDADDS = \ EXTRA_DIST = xmlrpcserver.py test_conf.sh noinst_PROGRAMS = xmlrpctest xml2sexprtest sexpr2xmltest virshtest conftest \ - reconnect xmconfigtest xencapstest qemuxml2argvtest qemuxml2xmltest + reconnect xmconfigtest xencapstest qemuxml2argvtest qemuxml2xmltest \ + nodeinfotest TESTS = xml2sexprtest sexpr2xmltest virshtest test_conf.sh xmconfigtest \ - xencapstest qemuxml2argvtest qemuxml2xmltest + xencapstest qemuxml2argvtest qemuxml2xmltest nodeinfotest if ENABLE_XEN_TESTS TESTS += reconnect endif @@ -99,6 +100,11 @@ xencapstest_SOURCES = \ xencapstest_LDFLAGS = xencapstest_LDADD = $(LDADDS) +nodeinfotest_SOURCES = \ + nodeinfotest.c testutils.h testutils.c +nodeinfotest_LDFLAGS = +nodeinfotest_LDADD = $(LDADDS) + reconnect_SOURCES = \ reconnect.c reconnect_LDFLAGS = Index: tests/nodeinfotest.c =================================================================== RCS file: tests/nodeinfotest.c diff -N tests/nodeinfotest.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/nodeinfotest.c 25 Jul 2007 14:28:21 -0000 @@ -0,0 +1,117 @@ +#include +#include + +#include "config.h" + +#include + +#include "testutils.h" +#include "internal.h" +#include "nodeinfo.h" + +static char *progname; + +#define MAX_FILE 4096 + +#ifdef __linux__ + +extern int linuxNodeInfoCPUPopulate(virConnectPtr conn, FILE *cpuinfo, virNodeInfoPtr nodeinfo); +extern int linuxNodeInfoMemPopulate(virConnectPtr conn, FILE *meminfo, virNodeInfoPtr nodeinfo); + +static int linuxTestCompareFiles(const char *cpuinfofile, const char *meminfofile, const char *outputfile) { + char actualData[MAX_FILE]; + char expectData[MAX_FILE]; + char *expect = &expectData[0]; + virNodeInfo nodeinfo; + FILE *cpuinfo, *meminfo; + + if (virtTestLoadFile(outputfile, &expect, MAX_FILE) < 0) + return -1; + + cpuinfo = fopen(cpuinfofile, "r"); + if (!cpuinfo) + return -1; + if (linuxNodeInfoCPUPopulate(NULL, cpuinfo, &nodeinfo) < 0) { + fclose(cpuinfo); + return -1; + } + fclose(cpuinfo); + + meminfo = fopen(meminfofile, "r"); + if (!meminfo) + return -1; + if (linuxNodeInfoMemPopulate(NULL, meminfo, &nodeinfo) < 0) { + fclose(meminfo); + return -1; + } + fclose(meminfo); + + snprintf(actualData, MAX_FILE, + "CPUs: %u, MHz: %u, Nodes: %u, Sockets: %u, Cores: %u, Threads: %u, Memory: %lu\n", + nodeinfo.cpus, nodeinfo.mhz, nodeinfo.nodes, nodeinfo.sockets, + nodeinfo.cores, nodeinfo.threads, nodeinfo.memory); + + if (STRNEQ(actualData, expectData)) { + if (getenv("DEBUG_TESTS")) { + printf("Expect %d '%s'\n", (int)strlen(expectData), expectData); + printf("Actual %d '%s'\n", (int)strlen(actualData), actualData); + } + return -1; + } + + return 0; +} + + +static int linuxTestNodeInfo(const void *data) { + char cpuinfo[PATH_MAX]; + char meminfo[PATH_MAX]; + char output[PATH_MAX]; + snprintf(cpuinfo, PATH_MAX, "nodeinfodata/linux-%s.cpuinfo", (const char*)data); + snprintf(meminfo, PATH_MAX, "nodeinfodata/linux-%s.meminfo", (const char*)data); + snprintf(output, PATH_MAX, "nodeinfodata/linux-%s.txt", (const char*)data); + return linuxTestCompareFiles(cpuinfo, meminfo, output); +} +#endif + + +int +main(int argc, char **argv) +{ + int ret = 0; +#ifdef __linux__ + int i; + const char *nodeData[] = { + "nodeinfo-1", + "nodeinfo-2", + "nodeinfo-3", + "nodeinfo-4", + "nodeinfo-5", + "nodeinfo-6", + }; + + progname = argv[0]; + + if (argc > 1) { + fprintf(stderr, "Usage: %s\n", progname); + exit(EXIT_FAILURE); + } + + virInitialize(); + + for (i = 0 ; i < (sizeof(nodeData)/sizeof(nodeData[0])) ; i++) + if (virtTestRun(nodeData[i], 1, linuxTestNodeInfo, nodeData[i]) != 0) + ret = -1; +#endif + + exit(ret==0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */