[libvirt] [PATCH v2 0/3] Gathering network interface statistics with openvswitch

Hi, The new code have been moved to virnetdevopenvswitch.c I have also sent the refactoring of virstat.c Regards, Mehdi Abaakouk (3): Gathering vhostuser interface stats with ovs virstat: fix signature of virstat helper Move virstat.c code to virnetdevtap.c src/Makefile.am | 1 - src/libvirt_private.syms | 5 +- src/libxl/libxl_driver.c | 4 +- src/lxc/lxc_driver.c | 3 +- src/openvz/openvz_driver.c | 4 +- src/qemu/qemu_driver.c | 31 +++++-- src/uml/uml_driver.c | 1 - src/util/virnetdevopenvswitch.c | 106 ++++++++++++++++++++++++ src/util/virnetdevopenvswitch.h | 4 + src/util/virnetdevtap.c | 143 ++++++++++++++++++++++++++++++++ src/util/virnetdevtap.h | 3 + src/util/virstats.c | 178 ---------------------------------------- src/util/virstats.h | 31 ------- src/xen/xen_hypervisor.c | 4 +- 14 files changed, 288 insertions(+), 230 deletions(-) delete mode 100644 src/util/virstats.c delete mode 100644 src/util/virstats.h -- 2.10.2

From: Mehdi Abaakouk <sileht@redhat.com> When vhostuser interfaces are used, the interface statistics are not available in /proc/net/dev. This change looks at the openvswitch interfaces statistics tables to provide this information for vhostuser interface. Note that in openvswitch world drop/error doesn't always make sense for some interface type. When these informations are not available we set them to 0 on the virDomainInterfaceStats. --- src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 29 ++++++++--- src/util/virnetdevopenvswitch.c | 106 ++++++++++++++++++++++++++++++++++++++++ src/util/virnetdevopenvswitch.h | 4 ++ 4 files changed, 133 insertions(+), 7 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index baff82b..aa27f78 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2034,6 +2034,7 @@ virNetDevMidonetUnbindPort; # util/virnetdevopenvswitch.h virNetDevOpenvswitchAddPort; virNetDevOpenvswitchGetMigrateData; +virNetDevOpenvswitchInterfaceStats; virNetDevOpenvswitchRemovePort; virNetDevOpenvswitchSetMigrateData; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d039255..87ca09d 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -66,6 +66,7 @@ #include "virhostcpu.h" #include "virhostmem.h" #include "virstats.h" +#include "virnetdevopenvswitch.h" #include "capabilities.h" #include "viralloc.h" #include "viruuid.h" @@ -10975,6 +10976,7 @@ qemuDomainInterfaceStats(virDomainPtr dom, virDomainInterfaceStatsPtr stats) { virDomainObjPtr vm; + virDomainNetDefPtr net = NULL; size_t i; int ret = -1; @@ -10994,16 +10996,21 @@ qemuDomainInterfaceStats(virDomainPtr dom, for (i = 0; i < vm->def->nnets; i++) { if (vm->def->nets[i]->ifname && STREQ(vm->def->nets[i]->ifname, path)) { - ret = 0; + net = vm->def->nets[i]; break; } } - if (ret == 0) - ret = virNetInterfaceStats(path, stats); - else + if (net) { + if (net->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER) { + ret = virNetDevOpenvswitchInterfaceStats(path, stats); + } else { + ret = virNetInterfaceStats(path, stats); + } + } else { virReportError(VIR_ERR_INVALID_ARG, _("invalid path, '%s' is not a known interface"), path); + } cleanup: virDomainObjEndAPI(&vm); @@ -19140,9 +19147,17 @@ qemuDomainGetStatsInterface(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, QEMU_ADD_NAME_PARAM(record, maxparams, "net", "name", i, dom->def->nets[i]->ifname); - if (virNetInterfaceStats(dom->def->nets[i]->ifname, &tmp) < 0) { - virResetLastError(); - continue; + if (dom->def->nets[i]->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER) { + if (virNetDevOpenvswitchInterfaceStats(dom->def->nets[i]->ifname, + &tmp) < 0) { + virResetLastError(); + continue; + } + } else { + if (virNetInterfaceStats(dom->def->nets[i]->ifname, &tmp) < 0) { + virResetLastError(); + continue; + } } QEMU_ADD_NET_PARAM(record, maxparams, i, diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c index 9283bbb..db8b542 100644 --- a/src/util/virnetdevopenvswitch.c +++ b/src/util/virnetdevopenvswitch.c @@ -24,6 +24,8 @@ #include <config.h> +#include <stdio.h> + #include "virnetdevopenvswitch.h" #include "vircommand.h" #include "viralloc.h" @@ -270,3 +272,107 @@ int virNetDevOpenvswitchSetMigrateData(char *migrate, const char *ifname) virCommandFree(cmd); return ret; } + +/** + * virNetDevOpenvswitchInterfaceStats: + * @ifname: the name of the interface + * @stats: the retreived domain interface stat + * + * Retrieves the OVS interfaces stats + * + * Returns 0 in case of success or -1 in case of failure + */ +int +virNetDevOpenvswitchInterfaceStats(const char *ifname, + virDomainInterfaceStatsPtr stats) +{ + virCommandPtr cmd = NULL; + char *output; + long long rx_bytes; + long long rx_packets; + long long tx_bytes; + long long tx_packets; + long long rx_errs; + long long rx_drop; + long long tx_errs; + long long tx_drop; + int ret = -1; + + // Just ensure the interface exists in ovs + cmd = virCommandNewArgList(OVSVSCTL, "--timeout=5", + "get", "Interface", ifname, + "name", NULL); + virCommandSetOutputBuffer(cmd, &output); + + if (virCommandRun(cmd, NULL) < 0) { + // no ovs-vsctl or interface 'ifname' doesn't exists in ovs + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Interface not found")); + goto cleanup; + } + + VIR_FREE(output); + virCommandFree(cmd); + + cmd = virCommandNewArgList(OVSVSCTL, "--timeout=5", + "get", "Interface", ifname, + "statistics:rx_bytes", + "statistics:rx_packets", + "statistics:tx_bytes", + "statistics:tx_packets", NULL); + virCommandSetOutputBuffer(cmd, &output); + + if (virCommandRun(cmd, NULL) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Interface doesn't have statistics")); + goto cleanup; + } + + // The TX/RX fields appear to be swapped here because this is the host view. + if (sscanf(output, "%lld\n%lld\n%lld\n%lld\n", + &tx_bytes, &tx_packets, &rx_bytes, &rx_packets) != 4) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Fail to parse ovs-vsctl output")); + goto cleanup; + } + + stats->rx_bytes = rx_bytes; + stats->rx_packets = rx_packets; + stats->tx_bytes = tx_bytes; + stats->tx_packets = tx_packets; + + VIR_FREE(output); + virCommandFree(cmd); + + cmd = virCommandNewArgList(OVSVSCTL, "--timeout=5", + "get", "Interface", ifname, + "statistics:rx_errors", + "statistics:rx_dropped", + "statistics:tx_errors", + "statistics:tx_dropped", NULL); + virCommandSetOutputBuffer(cmd, &output); + if (virCommandRun(cmd, NULL) < 0) { + // This interface don't have errors or dropped, so set them to 0 + stats->rx_errs = 0; + stats->rx_drop = 0; + stats->tx_errs = 0; + stats->tx_drop = 0; + } else if (sscanf(output, "%lld\n%lld\n%lld\n%lld\n", + &tx_errs, &tx_drop, &rx_errs, &rx_drop) == 4) { + stats->rx_errs = rx_errs; + stats->rx_drop = rx_drop; + stats->tx_errs = tx_errs; + stats->tx_drop = tx_drop; + ret = 0; + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Fail to parse ovs-vsctl output")); + goto cleanup; + } + ret = 0; + + cleanup: + VIR_FREE(output); + virCommandFree(cmd); + return ret; +} diff --git a/src/util/virnetdevopenvswitch.h b/src/util/virnetdevopenvswitch.h index 131be73..0f9e1df 100644 --- a/src/util/virnetdevopenvswitch.h +++ b/src/util/virnetdevopenvswitch.h @@ -48,4 +48,8 @@ int virNetDevOpenvswitchGetMigrateData(char **migrate, const char *ifname) int virNetDevOpenvswitchSetMigrateData(char *migrate, const char *ifname) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; +int virNetDevOpenvswitchInterfaceStats(const char *ifname, + virDomainInterfaceStatsPtr stats) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + #endif /* __VIR_NETDEV_OPENVSWITCH_H__ */ -- 2.10.2

From: Mehdi Abaakouk <sileht@redhat.com> In preparation to the code move to virnetdevtap.c, this change: * renames virNetInterfaceStats to virNetDevTapInterfaceStats * changes 'path' to 'ifname', to use the same vocable as other method in virnetdevtap.c. * Add the attributes checker --- src/libvirt_private.syms | 2 +- src/libxl/libxl_driver.c | 2 +- src/lxc/lxc_driver.c | 2 +- src/openvz/openvz_driver.c | 2 +- src/qemu/qemu_driver.c | 4 ++-- src/util/virstats.c | 22 +++++++++++----------- src/util/virstats.h | 5 +++-- src/xen/xen_hypervisor.c | 2 +- 8 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index aa27f78..0036cbd 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2367,7 +2367,7 @@ virSocketAddrSetIPv6AddrNetOrder; virSocketAddrSetPort; # util/virstats.h -virNetInterfaceStats; +virNetDevTapInterfaceStats; # util/virstorageencryption.h virStorageEncryptionFormat; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index b2f3b16..67f0e58 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -4982,7 +4982,7 @@ libxlDomainInterfaceStats(virDomainPtr dom, } if (ret == 0) - ret = virNetInterfaceStats(path, stats); + ret = virNetDevTapInterfaceStats(path, stats); else virReportError(VIR_ERR_INVALID_ARG, _("'%s' is not a known interface"), path); diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 4a0165a..526d40d 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2893,7 +2893,7 @@ lxcDomainInterfaceStats(virDomainPtr dom, } if (ret == 0) - ret = virNetInterfaceStats(path, stats); + ret = virNetDevTapInterfaceStats(path, stats); else virReportError(VIR_ERR_INVALID_ARG, _("Invalid path, '%s' is not a known interface"), path); diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 38a562e..7bd3acf 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -2024,7 +2024,7 @@ openvzDomainInterfaceStats(virDomainPtr dom, } if (ret == 0) - ret = virNetInterfaceStats(path, stats); + ret = virNetDevTapInterfaceStats(path, stats); else virReportError(VIR_ERR_INVALID_ARG, _("invalid path, '%s' is not a known interface"), path); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 87ca09d..38208b1 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -11005,7 +11005,7 @@ qemuDomainInterfaceStats(virDomainPtr dom, if (net->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER) { ret = virNetDevOpenvswitchInterfaceStats(path, stats); } else { - ret = virNetInterfaceStats(path, stats); + ret = virNetDevTapInterfaceStats(path, stats); } } else { virReportError(VIR_ERR_INVALID_ARG, @@ -19154,7 +19154,7 @@ qemuDomainGetStatsInterface(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, continue; } } else { - if (virNetInterfaceStats(dom->def->nets[i]->ifname, &tmp) < 0) { + if (virNetDevTapInterfaceStats(dom->def->nets[i]->ifname, &tmp) < 0) { virResetLastError(); continue; } diff --git a/src/util/virstats.c b/src/util/virstats.c index c4725ed..95b4c38 100644 --- a/src/util/virstats.c +++ b/src/util/virstats.c @@ -50,10 +50,10 @@ */ #ifdef __linux__ int -virNetInterfaceStats(const char *path, - virDomainInterfaceStatsPtr stats) +virNetDevTapInterfaceStats(const char *ifname, + virDomainInterfaceStatsPtr stats) { - int path_len; + int ifname_len; FILE *fp; char line[256], *colon; @@ -64,7 +64,7 @@ virNetInterfaceStats(const char *path, return -1; } - path_len = strlen(path); + ifname_len = strlen(ifname); while (fgets(line, sizeof(line), fp)) { long long dummy; @@ -84,8 +84,8 @@ virNetInterfaceStats(const char *path, colon = strchr(line, ':'); if (!colon) continue; *colon = '\0'; - if (colon-path_len >= line && - STREQ(colon-path_len, path)) { + if (colon-ifname_len >= line && + STREQ(colon-ifname_len, ifname)) { /* IMPORTANT NOTE! * /proc/net/dev vif<domid>.nn sees the network from the point * of view of dom0 / hypervisor. So bytes TRANSMITTED by dom0 @@ -121,8 +121,8 @@ virNetInterfaceStats(const char *path, } #elif defined(HAVE_GETIFADDRS) && defined(AF_LINK) int -virNetInterfaceStats(const char *path, - virDomainInterfaceStatsPtr stats) +virNetDevTapInterfaceStats(const char *ifname, + virDomainInterfaceStatsPtr stats) { struct ifaddrs *ifap, *ifa; struct if_data *ifd; @@ -138,7 +138,7 @@ virNetInterfaceStats(const char *path, if (ifa->ifa_addr->sa_family != AF_LINK) continue; - if (STREQ(ifa->ifa_name, path)) { + if (STREQ(ifa->ifa_name, ifname)) { ifd = (struct if_data *)ifa->ifa_data; stats->tx_bytes = ifd->ifi_ibytes; stats->tx_packets = ifd->ifi_ipackets; @@ -167,8 +167,8 @@ virNetInterfaceStats(const char *path, } #else int -virNetInterfaceStats(const char *path ATTRIBUTE_UNUSED, - virDomainInterfaceStatsPtr stats ATTRIBUTE_UNUSED) +virNetDevTapInterfaceStats(const char *ifname ATTRIBUTE_UNUSED, + virDomainInterfaceStatsPtr stats ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("interface stats not implemented on this platform")); diff --git a/src/util/virstats.h b/src/util/virstats.h index 69f4cf1..5b77197 100644 --- a/src/util/virstats.h +++ b/src/util/virstats.h @@ -25,7 +25,8 @@ # include "internal.h" -int virNetInterfaceStats(const char *path, - virDomainInterfaceStatsPtr stats); +int virNetDevTapInterfaceStats(const char *ifname, + virDomainInterfaceStatsPtr stats) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; #endif /* __STATS_LINUX_H__ */ diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c index 0177f83..efe5a8f 100644 --- a/src/xen/xen_hypervisor.c +++ b/src/xen/xen_hypervisor.c @@ -1466,7 +1466,7 @@ xenHypervisorDomainInterfaceStats(virDomainDefPtr def, return -1; } - return virNetInterfaceStats(path, stats); + return virNetDevTapInterfaceStats(path, stats); #else virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("/proc/net/dev: Interface not found")); -- 2.10.2

From: Mehdi Abaakouk <sileht@redhat.com> This is just a code move of virstat.c to virnetdevtap.c --- src/Makefile.am | 1 - src/libvirt_private.syms | 4 +- src/libxl/libxl_driver.c | 2 +- src/lxc/lxc_driver.c | 1 - src/openvz/openvz_driver.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/uml/uml_driver.c | 1 - src/util/virnetdevtap.c | 143 ++++++++++++++++++++++++++++++++++++ src/util/virnetdevtap.h | 3 + src/util/virstats.c | 178 --------------------------------------------- src/util/virstats.h | 32 -------- src/xen/xen_hypervisor.c | 2 +- 12 files changed, 151 insertions(+), 220 deletions(-) delete mode 100644 src/util/virstats.c delete mode 100644 src/util/virstats.h diff --git a/src/Makefile.am b/src/Makefile.am index aaba9e6..9c958aa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -167,7 +167,6 @@ UTIL_SOURCES = \ util/virsecret.c util/virsecret.h \ util/virsexpr.c util/virsexpr.h \ util/virsocketaddr.h util/virsocketaddr.c \ - util/virstats.c util/virstats.h \ util/virstorageencryption.c util/virstorageencryption.h \ util/virstoragefile.c util/virstoragefile.h \ util/virstring.h util/virstring.c \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 0036cbd..9bd4a8d 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2043,6 +2043,7 @@ virNetDevOpenvswitchSetMigrateData; virNetDevTapCreate; virNetDevTapCreateInBridgePort; virNetDevTapDelete; +virNetDevTapInterfaceStats; virNetDevTapGetName; virNetDevTapGetRealDeviceName; @@ -2366,9 +2367,6 @@ virSocketAddrSetIPv6Addr; virSocketAddrSetIPv6AddrNetOrder; virSocketAddrSetPort; -# util/virstats.h -virNetDevTapInterfaceStats; - # util/virstorageencryption.h virStorageEncryptionFormat; virStorageEncryptionFree; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 67f0e58..9454337 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -61,7 +61,7 @@ #include "virhostdev.h" #include "network/bridge_driver.h" #include "locking/domain_lock.h" -#include "virstats.h" +#include "virnetdevtap.h" #include "cpu/cpu.h" #define VIR_FROM_THIS VIR_FROM_LIBXL diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 526d40d..7a13c23 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -61,7 +61,6 @@ #include "virhostcpu.h" #include "virhostmem.h" #include "viruuid.h" -#include "virstats.h" #include "virhook.h" #include "virfile.h" #include "virpidfile.h" diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 7bd3acf..5e549e00 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -57,7 +57,7 @@ #include "virlog.h" #include "vircommand.h" #include "viruri.h" -#include "virstats.h" +#include "virnetdevtap.h" #include "virstring.h" #define VIR_FROM_THIS VIR_FROM_OPENVZ diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 38208b1..1124429 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -65,7 +65,7 @@ #include "nodeinfo.h" #include "virhostcpu.h" #include "virhostmem.h" -#include "virstats.h" +#include "virnetdevtap.h" #include "virnetdevopenvswitch.h" #include "capabilities.h" #include "viralloc.h" diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 4f4a69b..d3fb08a 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -48,7 +48,6 @@ #include "nodeinfo.h" #include "virhostcpu.h" #include "virhostmem.h" -#include "virstats.h" #include "capabilities.h" #include "viralloc.h" #include "viruuid.h" diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c index 7488a4c..85c0045 100644 --- a/src/util/virnetdevtap.c +++ b/src/util/virnetdevtap.c @@ -33,7 +33,13 @@ #include "viralloc.h" #include "virlog.h" #include "virstring.h" +#include "datatypes.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <regex.h> #include <dirent.h> #include <sys/types.h> #include <sys/ioctl.h> @@ -44,6 +50,9 @@ #elif defined(__FreeBSD__) # include <net/if_tap.h> #endif +#if defined(HAVE_GETIFADDRS) && defined(AF_LINK) +# include <ifaddrs.h> +#endif #define VIR_FROM_THIS VIR_FROM_NONE @@ -601,3 +610,137 @@ int virNetDevTapCreateInBridgePort(const char *brname, return -1; } + +/*-------------------- interface stats --------------------*/ +/* Just reads the named interface, so not Xen or QEMU-specific. + * NB. Caller must check that libvirt user is trying to query + * the interface of a domain they own. We do no such checking. + */ +#ifdef __linux__ +int +virNetDevTapInterfaceStats(const char *ifname, + virDomainInterfaceStatsPtr stats) +{ + int ifname_len; + FILE *fp; + char line[256], *colon; + + fp = fopen("/proc/net/dev", "r"); + if (!fp) { + virReportSystemError(errno, "%s", + _("Could not open /proc/net/dev")); + return -1; + } + + ifname_len = strlen(ifname); + + while (fgets(line, sizeof(line), fp)) { + long long dummy; + long long rx_bytes; + long long rx_packets; + long long rx_errs; + long long rx_drop; + long long tx_bytes; + long long tx_packets; + long long tx_errs; + long long tx_drop; + + /* The line looks like: + * " eth0:..." + * Split it at the colon. + */ + colon = strchr(line, ':'); + if (!colon) continue; + *colon = '\0'; + if (colon-ifname_len >= line && + STREQ(colon-ifname_len, ifname)) { + /* IMPORTANT NOTE! + * /proc/net/dev vif<domid>.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(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, + &rx_bytes, &rx_packets, &rx_errs, &rx_drop, + &dummy, &dummy, &dummy, &dummy) != 16) + continue; + + stats->rx_bytes = rx_bytes; + stats->rx_packets = rx_packets; + stats->rx_errs = rx_errs; + stats->rx_drop = rx_drop; + stats->tx_bytes = tx_bytes; + stats->tx_packets = tx_packets; + stats->tx_errs = tx_errs; + stats->tx_drop = tx_drop; + VIR_FORCE_FCLOSE(fp); + + return 0; + } + } + VIR_FORCE_FCLOSE(fp); + + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("/proc/net/dev: Interface not found")); + return -1; +} +#elif defined(HAVE_GETIFADDRS) && defined(AF_LINK) +int +virNetDevTapInterfaceStats(const char *ifname, + virDomainInterfaceStatsPtr stats) +{ + struct ifaddrs *ifap, *ifa; + struct if_data *ifd; + int ret = -1; + + if (getifaddrs(&ifap) < 0) { + virReportSystemError(errno, "%s", + _("Could not get interface list")); + return -1; + } + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family != AF_LINK) + continue; + + if (STREQ(ifa->ifa_name, ifname)) { + ifd = (struct if_data *)ifa->ifa_data; + stats->tx_bytes = ifd->ifi_ibytes; + stats->tx_packets = ifd->ifi_ipackets; + stats->tx_errs = ifd->ifi_ierrors; + stats->tx_drop = ifd->ifi_iqdrops; + stats->rx_bytes = ifd->ifi_obytes; + stats->rx_packets = ifd->ifi_opackets; + stats->rx_errs = ifd->ifi_oerrors; +# ifdef HAVE_STRUCT_IF_DATA_IFI_OQDROPS + stats->rx_drop = ifd->ifi_oqdrops; +# else + stats->rx_drop = 0; +# endif + + ret = 0; + break; + } + } + + if (ret < 0) + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Interface not found")); + + freeifaddrs(ifap); + return ret; +} +#else +int +virNetDevTapInterfaceStats(const char *ifname ATTRIBUTE_UNUSED, + virDomainInterfaceStatsPtr stats ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("interface stats not implemented on this platform")); + return -1; +} + +#endif /* __linux__ */ diff --git a/src/util/virnetdevtap.h b/src/util/virnetdevtap.h index 20dec58..259e7c9 100644 --- a/src/util/virnetdevtap.h +++ b/src/util/virnetdevtap.h @@ -75,5 +75,8 @@ int virNetDevTapCreateInBridgePort(const char *brname, ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK; +int virNetDevTapInterfaceStats(const char *ifname, + virDomainInterfaceStatsPtr stats) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; #endif /* __VIR_NETDEV_TAP_H__ */ diff --git a/src/util/virstats.c b/src/util/virstats.c deleted file mode 100644 index 95b4c38..0000000 --- a/src/util/virstats.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * virstats.c: Block and network stats. - * - * Copyright (C) 2007-2010, 2014 Red Hat, Inc. - * - * 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, see - * <http://www.gnu.org/licenses/>. - * - * Richard W.M. Jones <rjones@redhat.com> - */ - -#include <config.h> - -#include <stdio.h> -#include <stdlib.h> -#include <fcntl.h> -#include <string.h> -#include <unistd.h> -#include <regex.h> - -#if defined(HAVE_GETIFADDRS) && defined(AF_LINK) -# include <net/if.h> -# include <ifaddrs.h> -#endif - -#include "virerror.h" -#include "datatypes.h" -#include "virstats.h" -#include "viralloc.h" -#include "virfile.h" - -#define VIR_FROM_THIS VIR_FROM_STATS_LINUX - - -/*-------------------- interface stats --------------------*/ -/* Just reads the named interface, so not Xen or QEMU-specific. - * NB. Caller must check that libvirt user is trying to query - * the interface of a domain they own. We do no such checking. - */ -#ifdef __linux__ -int -virNetDevTapInterfaceStats(const char *ifname, - virDomainInterfaceStatsPtr stats) -{ - int ifname_len; - FILE *fp; - char line[256], *colon; - - fp = fopen("/proc/net/dev", "r"); - if (!fp) { - virReportSystemError(errno, "%s", - _("Could not open /proc/net/dev")); - return -1; - } - - ifname_len = strlen(ifname); - - while (fgets(line, sizeof(line), fp)) { - long long dummy; - long long rx_bytes; - long long rx_packets; - long long rx_errs; - long long rx_drop; - long long tx_bytes; - long long tx_packets; - long long tx_errs; - long long tx_drop; - - /* The line looks like: - * " eth0:..." - * Split it at the colon. - */ - colon = strchr(line, ':'); - if (!colon) continue; - *colon = '\0'; - if (colon-ifname_len >= line && - STREQ(colon-ifname_len, ifname)) { - /* IMPORTANT NOTE! - * /proc/net/dev vif<domid>.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(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, - &rx_bytes, &rx_packets, &rx_errs, &rx_drop, - &dummy, &dummy, &dummy, &dummy) != 16) - continue; - - stats->rx_bytes = rx_bytes; - stats->rx_packets = rx_packets; - stats->rx_errs = rx_errs; - stats->rx_drop = rx_drop; - stats->tx_bytes = tx_bytes; - stats->tx_packets = tx_packets; - stats->tx_errs = tx_errs; - stats->tx_drop = tx_drop; - VIR_FORCE_FCLOSE(fp); - - return 0; - } - } - VIR_FORCE_FCLOSE(fp); - - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("/proc/net/dev: Interface not found")); - return -1; -} -#elif defined(HAVE_GETIFADDRS) && defined(AF_LINK) -int -virNetDevTapInterfaceStats(const char *ifname, - virDomainInterfaceStatsPtr stats) -{ - struct ifaddrs *ifap, *ifa; - struct if_data *ifd; - int ret = -1; - - if (getifaddrs(&ifap) < 0) { - virReportSystemError(errno, "%s", - _("Could not get interface list")); - return -1; - } - - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_addr->sa_family != AF_LINK) - continue; - - if (STREQ(ifa->ifa_name, ifname)) { - ifd = (struct if_data *)ifa->ifa_data; - stats->tx_bytes = ifd->ifi_ibytes; - stats->tx_packets = ifd->ifi_ipackets; - stats->tx_errs = ifd->ifi_ierrors; - stats->tx_drop = ifd->ifi_iqdrops; - stats->rx_bytes = ifd->ifi_obytes; - stats->rx_packets = ifd->ifi_opackets; - stats->rx_errs = ifd->ifi_oerrors; -# ifdef HAVE_STRUCT_IF_DATA_IFI_OQDROPS - stats->rx_drop = ifd->ifi_oqdrops; -# else - stats->rx_drop = 0; -# endif - - ret = 0; - break; - } - } - - if (ret < 0) - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Interface not found")); - - freeifaddrs(ifap); - return ret; -} -#else -int -virNetDevTapInterfaceStats(const char *ifname ATTRIBUTE_UNUSED, - virDomainInterfaceStatsPtr stats ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("interface stats not implemented on this platform")); - return -1; -} - -#endif /* __linux__ */ diff --git a/src/util/virstats.h b/src/util/virstats.h deleted file mode 100644 index 5b77197..0000000 --- a/src/util/virstats.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * virstats.h: Block and network stats. - * - * Copyright (C) 2007 Red Hat, Inc. - * - * 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, see - * <http://www.gnu.org/licenses/>. - * - * Richard W.M. Jones <rjones@redhat.com> - */ - -#ifndef __STATS_LINUX_H__ -# define __STATS_LINUX_H__ - -# include "internal.h" - -int virNetDevTapInterfaceStats(const char *ifname, - virDomainInterfaceStatsPtr stats) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; - -#endif /* __STATS_LINUX_H__ */ diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c index efe5a8f..bce7b56 100644 --- a/src/xen/xen_hypervisor.c +++ b/src/xen/xen_hypervisor.c @@ -68,7 +68,7 @@ #include "xen_driver.h" #include "xen_hypervisor.h" #include "xs_internal.h" -#include "virstats.h" +#include "virnetdevtap.h" #include "block_stats.h" #include "xend_internal.h" #include "virbuffer.h" -- 2.10.2
participants (1)
-
Mehdi Abaakouk