diff --git a/ChangeLog b/ChangeLog index 04b37e9c76..e019150fac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Thu Nov 15 17:43:00 UTC 2007 Richard W.M. Jones + + * 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 * docs/hvsupport.html, docs/libvir.html: Document HV support diff --git a/src/qemu_driver.c b/src/qemu_driver.c index 62a1f6ba98..da690fa766 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -55,6 +55,7 @@ #include "qemu_driver.h" #include "qemu_conf.h" #include "nodeinfo.h" +#include "stats_linux.h" static int qemudShutdown(void); @@ -2479,6 +2480,65 @@ static int qemudDomainSetAutostart(virDomainPtr dom, 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, const unsigned char *uuid) { struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData; @@ -2822,7 +2882,7 @@ static virDriver qemuDriver = { NULL, /* domainMigratePerform */ NULL, /* domainMigrateFinish */ NULL, /* domainBlockStats */ - NULL, /* domainInterfaceStats */ + qemudDomainInterfaceStats, /* domainInterfaceStats */ NULL, /* nodeGetCellsFreeMemory */ NULL, /* getFreeMemory */ }; diff --git a/src/stats_linux.c b/src/stats_linux.c index 125af45fcd..f35d5dd4e1 100644 --- a/src/stats_linux.c +++ b/src/stats_linux.c @@ -291,7 +291,7 @@ linuxDomainInterfaceStats (virConnectPtr conn, const char *path, { int path_len; FILE *fp; - char line[256]; + char line[256], *colon; fp = fopen ("/proc/net/dev", "r"); if (!fp) { @@ -313,16 +313,22 @@ linuxDomainInterfaceStats (virConnectPtr conn, const char *path, long long tx_errs; long long tx_drop; - if (STREQLEN (line, path, path_len) && - line[path_len] == ':' && - line[path_len+1] == ' ') { + /* The line looks like: + * " eth0:..." + * 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! * /proc/net/dev vif.nn sees the network from the point * of view of dom0 / hypervisor. So bytes TRANSMITTED by dom0 * are bytes RECEIVED by the domain. That's why the TX/RX fields * 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", &tx_bytes, &tx_packets, &tx_errs, &tx_drop, &dummy, &dummy, &dummy, &dummy,