Thu Nov 15 17:43:00 UTC 2007 Richard W.M. Jones <rjones@redhat.com>

* src/stats_linux.c: Fix parsing of short interface names
	  occurring in the /proc/net/dev file.
	* src/qemu_driver.c: Collect interface stats for QEMU & KVM
	  domains.
This commit is contained in:
Richard W.M. Jones 2007-11-15 17:45:44 +00:00
parent 7a66394fcb
commit e714bb67ca
3 changed files with 79 additions and 6 deletions

View File

@ -1,3 +1,10 @@
Thu Nov 15 17:43:00 UTC 2007 Richard W.M. Jones <rjones@redhat.com>
* src/stats_linux.c: Fix parsing of short interface names
occurring in the /proc/net/dev file.
* src/qemu_driver.c: Collect interface stats for QEMU & KVM
domains.
Thu Nov 15 17:40:15 UTC 2007 Richard W.M. Jones <rjones@redhat.com> Thu Nov 15 17:40:15 UTC 2007 Richard W.M. Jones <rjones@redhat.com>
* docs/hvsupport.html, docs/libvir.html: Document HV support * docs/hvsupport.html, docs/libvir.html: Document HV support

View File

@ -55,6 +55,7 @@
#include "qemu_driver.h" #include "qemu_driver.h"
#include "qemu_conf.h" #include "qemu_conf.h"
#include "nodeinfo.h" #include "nodeinfo.h"
#include "stats_linux.h"
static int qemudShutdown(void); static int qemudShutdown(void);
@ -2479,6 +2480,65 @@ static int qemudDomainSetAutostart(virDomainPtr dom,
return 0; return 0;
} }
static int
qemudDomainInterfaceStats (virDomainPtr dom,
const char *path,
struct _virDomainInterfaceStats *stats)
{
#ifdef __linux__
struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
struct qemud_vm *vm = qemudFindVMByID (driver, dom->id);
struct qemud_vm_net_def *net;
if (!vm) {
qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
"no domain with matching id %d", dom->id);
return -1;
}
if (!qemudIsActiveVM(vm)) {
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
"domain is not running");
return -1;
}
if (!path || path[0] == '\0') {
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
"NULL or empty path");
return -1;
}
/* Check the path is one of the domain's network interfaces. */
for (net = vm->def->nets; net; net = net->next) {
switch (net->type) {
case QEMUD_NET_NETWORK:
if (STREQ (net->dst.network.ifname, path))
goto ok;
break;
case QEMUD_NET_ETHERNET:
if (STREQ (net->dst.ethernet.ifname, path))
goto ok;
break;
case QEMUD_NET_BRIDGE:
if (STREQ (net->dst.bridge.ifname, path))
goto ok;
break;
}
}
qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
"invalid path, '%s' is not a known interface", path);
return -1;
ok:
return linuxDomainInterfaceStats (dom->conn, path, stats);
#else
qemudReportError (dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
"%s", __FUNCTION__);
return -1;
#endif
}
static virNetworkPtr qemudNetworkLookupByUUID(virConnectPtr conn ATTRIBUTE_UNUSED, static virNetworkPtr qemudNetworkLookupByUUID(virConnectPtr conn ATTRIBUTE_UNUSED,
const unsigned char *uuid) { const unsigned char *uuid) {
struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData; struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData;
@ -2822,7 +2882,7 @@ static virDriver qemuDriver = {
NULL, /* domainMigratePerform */ NULL, /* domainMigratePerform */
NULL, /* domainMigrateFinish */ NULL, /* domainMigrateFinish */
NULL, /* domainBlockStats */ NULL, /* domainBlockStats */
NULL, /* domainInterfaceStats */ qemudDomainInterfaceStats, /* domainInterfaceStats */
NULL, /* nodeGetCellsFreeMemory */ NULL, /* nodeGetCellsFreeMemory */
NULL, /* getFreeMemory */ NULL, /* getFreeMemory */
}; };

View File

@ -291,7 +291,7 @@ linuxDomainInterfaceStats (virConnectPtr conn, const char *path,
{ {
int path_len; int path_len;
FILE *fp; FILE *fp;
char line[256]; char line[256], *colon;
fp = fopen ("/proc/net/dev", "r"); fp = fopen ("/proc/net/dev", "r");
if (!fp) { if (!fp) {
@ -313,16 +313,22 @@ linuxDomainInterfaceStats (virConnectPtr conn, const char *path,
long long tx_errs; long long tx_errs;
long long tx_drop; long long tx_drop;
if (STREQLEN (line, path, path_len) && /* The line looks like:
line[path_len] == ':' && * " eth0:..."
line[path_len+1] == ' ') { * Split it at the colon.
*/
colon = strchr (line, ':');
if (!colon) continue;
*colon = '\0';
if (colon-path_len >= line &&
STREQ (colon-path_len, path)) {
/* IMPORTANT NOTE! /* IMPORTANT NOTE!
* /proc/net/dev vif<domid>.nn sees the network from the point * /proc/net/dev vif<domid>.nn sees the network from the point
* of view of dom0 / hypervisor. So bytes TRANSMITTED by dom0 * of view of dom0 / hypervisor. So bytes TRANSMITTED by dom0
* are bytes RECEIVED by the domain. That's why the TX/RX fields * are bytes RECEIVED by the domain. That's why the TX/RX fields
* appear to be swapped here. * appear to be swapped here.
*/ */
if (sscanf (&line[path_len+2], if (sscanf (colon+1,
"%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld", "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld",
&tx_bytes, &tx_packets, &tx_errs, &tx_drop, &tx_bytes, &tx_packets, &tx_errs, &tx_drop,
&dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy,