mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-10-29 17:33:09 +00:00
Wed Nov 14 11:55:00 UTC 2007 Richard W.M. Jones <rjones@redhat.com>
* src/stats_linux.c, src/stats_linux.h, src_xen_internal.c: Abstract out the Linux-specific statistics. Fixed parsing of 64 bit numbers. * src/Makefile.am: Updated Makefile for new files.
This commit is contained in:
parent
88f28d6980
commit
3ba58f158d
@ -1,3 +1,10 @@
|
|||||||
|
Wed Nov 14 11:55:00 UTC 2007 Richard W.M. Jones <rjones@redhat.com>
|
||||||
|
|
||||||
|
* src/stats_linux.c, src/stats_linux.h, src_xen_internal.c:
|
||||||
|
Abstract out the Linux-specific statistics. Fixed parsing
|
||||||
|
of 64 bit numbers.
|
||||||
|
* src/Makefile.am: Updated Makefile for new files.
|
||||||
|
|
||||||
Wed Nov 14 11:36:00 UTC 2007 Richard W.M. Jones <rjones@redhat.com>
|
Wed Nov 14 11:36:00 UTC 2007 Richard W.M. Jones <rjones@redhat.com>
|
||||||
|
|
||||||
* src/libvirt.c and all internal driver interfaces: Parse the
|
* src/libvirt.c and all internal driver interfaces: Parse the
|
||||||
|
@ -42,6 +42,7 @@ CLIENT_SOURCES = \
|
|||||||
xen_internal.c xen_internal.h \
|
xen_internal.c xen_internal.h \
|
||||||
xs_internal.c xs_internal.h \
|
xs_internal.c xs_internal.h \
|
||||||
xend_internal.c xend_internal.h \
|
xend_internal.c xend_internal.h \
|
||||||
|
stats_linux.c stats_linux.h \
|
||||||
sexpr.c sexpr.h \
|
sexpr.c sexpr.h \
|
||||||
virterror.c \
|
virterror.c \
|
||||||
driver.h \
|
driver.h \
|
||||||
@ -53,8 +54,8 @@ CLIENT_SOURCES = \
|
|||||||
iptables.c iptables.h \
|
iptables.c iptables.h \
|
||||||
uuid.c uuid.h \
|
uuid.c uuid.h \
|
||||||
qemu_driver.c qemu_driver.h \
|
qemu_driver.c qemu_driver.h \
|
||||||
qemu_conf.c qemu_conf.h \
|
qemu_conf.c qemu_conf.h \
|
||||||
openvz_conf.c openvz_conf.h \
|
openvz_conf.c openvz_conf.h \
|
||||||
openvz_driver.c openvz_driver.h \
|
openvz_driver.c openvz_driver.h \
|
||||||
nodeinfo.h nodeinfo.c \
|
nodeinfo.h nodeinfo.c \
|
||||||
util.c util.h
|
util.c util.h
|
||||||
|
364
src/stats_linux.c
Normal file
364
src/stats_linux.c
Normal file
@ -0,0 +1,364 @@
|
|||||||
|
/*
|
||||||
|
* Linux block and network stats.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* See COPYING.LIB for the License of this software
|
||||||
|
*
|
||||||
|
* Richard W.M. Jones <rjones@redhat.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
/* This file only applies on Linux. */
|
||||||
|
#ifdef __linux__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <xs.h>
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
#include "xen_unified.h"
|
||||||
|
#include "stats_linux.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* statsErrorFunc:
|
||||||
|
* @conn: the connection
|
||||||
|
* @error: the error number
|
||||||
|
* @func: the function failing
|
||||||
|
* @info: extra information string
|
||||||
|
* @value: extra information number
|
||||||
|
*
|
||||||
|
* Handle a stats error.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
statsErrorFunc (virConnectPtr conn,
|
||||||
|
virErrorNumber error, const char *func, const char *info,
|
||||||
|
int value)
|
||||||
|
{
|
||||||
|
char fullinfo[1000];
|
||||||
|
const char *errmsg;
|
||||||
|
|
||||||
|
errmsg = __virErrorMsg(error, info);
|
||||||
|
if (func != NULL) {
|
||||||
|
snprintf(fullinfo, sizeof (fullinfo) - 1, "%s: %s", func, info);
|
||||||
|
fullinfo[sizeof (fullinfo) - 1] = 0;
|
||||||
|
info = fullinfo;
|
||||||
|
}
|
||||||
|
__virRaiseError(conn, NULL, NULL, VIR_FROM_XEN, error, VIR_ERR_ERROR,
|
||||||
|
errmsg, info, NULL, value, 0, errmsg, info,
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_XEN
|
||||||
|
/*-------------------- Xen: block stats --------------------*/
|
||||||
|
|
||||||
|
#include <linux/major.h>
|
||||||
|
|
||||||
|
/* This is normally defined in <linux/major.h> but previously we
|
||||||
|
* hard-coded it. So if it's not defined, hard-code again.
|
||||||
|
*/
|
||||||
|
#ifndef XENVBD_MAJOR
|
||||||
|
#define XENVBD_MAJOR 202
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int
|
||||||
|
xstrtoint64 (char const *s, int base, int64_t *result)
|
||||||
|
{
|
||||||
|
long long int lli;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
lli = strtoll (s, &p, base);
|
||||||
|
if (errno || !(*p == 0 || *p == '\n') || p == s || (int64_t) lli != lli)
|
||||||
|
return -1;
|
||||||
|
*result = lli;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64_t
|
||||||
|
read_stat (const char *path)
|
||||||
|
{
|
||||||
|
char str[64];
|
||||||
|
int64_t r;
|
||||||
|
int i;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen (path, "r");
|
||||||
|
if (!fp)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* read, but don't bail out before closing */
|
||||||
|
i = fread (str, 1, sizeof str - 1, fp);
|
||||||
|
|
||||||
|
if (fclose (fp) != 0 /* disk error */
|
||||||
|
|| i < 1) /* ensure we read at least one byte */
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
str[i] = '\0'; /* make sure the string is nul-terminated */
|
||||||
|
if (xstrtoint64 (str, 10, &r) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64_t
|
||||||
|
read_bd_stat (int device, int domid, const char *str)
|
||||||
|
{
|
||||||
|
char path[PATH_MAX];
|
||||||
|
int64_t r;
|
||||||
|
|
||||||
|
snprintf (path, sizeof path,
|
||||||
|
"/sys/devices/xen-backend/vbd-%d-%d/statistics/%s",
|
||||||
|
domid, device, str);
|
||||||
|
r = read_stat (path);
|
||||||
|
if (r >= 0) return r;
|
||||||
|
|
||||||
|
snprintf (path, sizeof path,
|
||||||
|
"/sys/devices/xen-backend/tap-%d-%d/statistics/%s",
|
||||||
|
domid, device, str);
|
||||||
|
r = read_stat (path);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In Xenstore, /local/domain/0/backend/vbd/<domid>/<device>/state,
|
||||||
|
* if available, must be XenbusStateConnected (= 4), otherwise there
|
||||||
|
* is no connected device.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
check_bd_connected (xenUnifiedPrivatePtr priv, int device, int domid)
|
||||||
|
{
|
||||||
|
char s[256], *rs;
|
||||||
|
int r;
|
||||||
|
unsigned len = 0;
|
||||||
|
|
||||||
|
/* This code assumes we're connected if we can't get to
|
||||||
|
* xenstore, etc.
|
||||||
|
*/
|
||||||
|
if (!priv->xshandle) return 1;
|
||||||
|
snprintf (s, sizeof s, "/local/domain/0/backend/vbd/%d/%d/state",
|
||||||
|
domid, device);
|
||||||
|
s[sizeof s - 1] = '\0';
|
||||||
|
|
||||||
|
rs = xs_read (priv->xshandle, 0, s, &len);
|
||||||
|
if (!rs) return 1;
|
||||||
|
if (len == 0) {
|
||||||
|
/* Hmmm ... we can get to xenstore but it returns an empty
|
||||||
|
* string instead of an error. Assume it's not connected
|
||||||
|
* in this case.
|
||||||
|
*/
|
||||||
|
free (rs);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = STREQ (rs, "4");
|
||||||
|
free (rs);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
read_bd_stats (virConnectPtr conn, xenUnifiedPrivatePtr priv,
|
||||||
|
int device, int domid, struct _virDomainBlockStats *stats)
|
||||||
|
{
|
||||||
|
stats->rd_req = read_bd_stat (device, domid, "rd_req");
|
||||||
|
stats->rd_bytes = read_bd_stat (device, domid, "rd_sect");
|
||||||
|
stats->wr_req = read_bd_stat (device, domid, "wr_req");
|
||||||
|
stats->wr_bytes = read_bd_stat (device, domid, "wr_sect");
|
||||||
|
stats->errs = read_bd_stat (device, domid, "oo_req");
|
||||||
|
|
||||||
|
/* None of the files were found - it's likely that this version
|
||||||
|
* of Xen is an old one which just doesn't support stats collection.
|
||||||
|
*/
|
||||||
|
if (stats->rd_req == -1 && stats->rd_bytes == -1 &&
|
||||||
|
stats->wr_req == -1 && stats->wr_bytes == -1 &&
|
||||||
|
stats->errs == -1) {
|
||||||
|
statsErrorFunc (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__,
|
||||||
|
"Failed to read any block statistics", domid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If stats are all zero then either there really isn't any block
|
||||||
|
* device activity, or there is no connected front end device
|
||||||
|
* in which case there are no stats.
|
||||||
|
*/
|
||||||
|
if (stats->rd_req == 0 && stats->rd_bytes == 0 &&
|
||||||
|
stats->wr_req == 0 && stats->wr_bytes == 0 &&
|
||||||
|
stats->errs == 0 &&
|
||||||
|
!check_bd_connected (priv, device, domid)) {
|
||||||
|
statsErrorFunc (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__,
|
||||||
|
"Frontend block device not connected", domid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 'Bytes' was really sectors when we read it. Scale up by
|
||||||
|
* an assumed sector size.
|
||||||
|
*/
|
||||||
|
if (stats->rd_bytes > 0) {
|
||||||
|
if (stats->rd_bytes >= 1L<<(63-9)) {
|
||||||
|
statsErrorFunc (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__,
|
||||||
|
"stats->rd_bytes would overflow 64 bit counter",
|
||||||
|
domid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
stats->rd_bytes *= 512;
|
||||||
|
}
|
||||||
|
if (stats->wr_bytes > 0) {
|
||||||
|
if (stats->wr_bytes >= 1L<<(63-9)) {
|
||||||
|
statsErrorFunc (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__,
|
||||||
|
"stats->wr_bytes would overflow 64 bit counter",
|
||||||
|
domid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
stats->wr_bytes *= 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xenLinuxDomainBlockStats (xenUnifiedPrivatePtr priv,
|
||||||
|
virDomainPtr dom,
|
||||||
|
const char *path,
|
||||||
|
struct _virDomainBlockStats *stats)
|
||||||
|
{
|
||||||
|
int minor, device;
|
||||||
|
|
||||||
|
/* Paravirt domains:
|
||||||
|
* Paths have the form "xvd[a-]" and map to paths
|
||||||
|
* /sys/devices/xen-backend/(vbd|tap)-domid-major:minor/
|
||||||
|
* statistics/(rd|wr|oo)_req.
|
||||||
|
* The major:minor is in this case fixed as 202*256 + minor*16
|
||||||
|
* where minor is 0 for xvda, 1 for xvdb and so on.
|
||||||
|
*
|
||||||
|
* XXX Not clear what happens to device numbers for devices
|
||||||
|
* >= xdvo (minor >= 16), which would otherwise overflow the
|
||||||
|
* 256 minor numbers assigned to this major number. So we
|
||||||
|
* currently limit you to the first 16 block devices per domain.
|
||||||
|
*/
|
||||||
|
if (strlen (path) == 4 &&
|
||||||
|
STREQLEN (path, "xvd", 3)) {
|
||||||
|
if ((minor = path[3] - 'a') < 0 || minor >= 16) {
|
||||||
|
statsErrorFunc (dom->conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
|
||||||
|
"invalid path, should be xvda, xvdb, etc.",
|
||||||
|
dom->id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
device = XENVBD_MAJOR * 256 + minor * 16;
|
||||||
|
|
||||||
|
return read_bd_stats (dom->conn, priv, device, dom->id, stats);
|
||||||
|
}
|
||||||
|
/* Fullvirt domains:
|
||||||
|
* hda, hdb etc map to major = HD_MAJOR*256 + minor*16.
|
||||||
|
*
|
||||||
|
* See comment above about devices >= hdo.
|
||||||
|
*/
|
||||||
|
else if (strlen (path) == 3 &&
|
||||||
|
STREQLEN (path, "hd", 2)) {
|
||||||
|
if ((minor = path[2] - 'a') < 0 || minor >= 16) {
|
||||||
|
statsErrorFunc (dom->conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
|
||||||
|
"invalid path, should be hda, hdb, etc.",
|
||||||
|
dom->id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
device = HD_MAJOR * 256 + minor * 16;
|
||||||
|
|
||||||
|
return read_bd_stats (dom->conn, priv, device, dom->id, stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, unsupported device name. */
|
||||||
|
statsErrorFunc (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__,
|
||||||
|
"unsupported path (use xvda, hda, etc.)", dom->id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* WITH_XEN */
|
||||||
|
|
||||||
|
/*-------------------- 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
linuxDomainInterfaceStats (virConnectPtr conn, const char *path,
|
||||||
|
struct _virDomainInterfaceStats *stats)
|
||||||
|
{
|
||||||
|
int path_len;
|
||||||
|
FILE *fp;
|
||||||
|
char line[256];
|
||||||
|
|
||||||
|
fp = fopen ("/proc/net/dev", "r");
|
||||||
|
if (!fp) {
|
||||||
|
statsErrorFunc (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__,
|
||||||
|
"/proc/net/dev", errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
path_len = strlen (path);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (STREQLEN (line, path, path_len) &&
|
||||||
|
line[path_len] == ':' &&
|
||||||
|
line[path_len+1] == ' ') {
|
||||||
|
/* 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 (&line[path_len+2],
|
||||||
|
"%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;
|
||||||
|
fclose (fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose (fp);
|
||||||
|
|
||||||
|
statsErrorFunc (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__,
|
||||||
|
"/proc/net/dev: Interface not found", 0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __linux__ */
|
||||||
|
/*
|
||||||
|
* vim: set tabstop=4:
|
||||||
|
* vim: set shiftwidth=4:
|
||||||
|
* vim: set expandtab:
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* indent-tabs-mode: nil
|
||||||
|
* c-indent-level: 4
|
||||||
|
* c-basic-offset: 4
|
||||||
|
* tab-width: 4
|
||||||
|
* End:
|
||||||
|
*/
|
39
src/stats_linux.h
Normal file
39
src/stats_linux.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Linux block and network stats.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* See COPYING.LIB for the License of this software
|
||||||
|
*
|
||||||
|
* Richard W.M. Jones <rjones@redhat.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __STATS_LINUX_H__
|
||||||
|
#define __STATS_LINUX_H__
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
|
||||||
|
#include "xen_unified.h"
|
||||||
|
|
||||||
|
extern int xenLinuxDomainBlockStats (xenUnifiedPrivatePtr priv,
|
||||||
|
virDomainPtr dom, const char *path,
|
||||||
|
struct _virDomainBlockStats *stats);
|
||||||
|
extern int linuxDomainInterfaceStats (virConnectPtr conn, const char *path,
|
||||||
|
struct _virDomainInterfaceStats *stats);
|
||||||
|
|
||||||
|
#endif /* __linux__ */
|
||||||
|
|
||||||
|
#endif /* __STATS_LINUX_H__ */
|
||||||
|
/*
|
||||||
|
* vim: set tabstop=4:
|
||||||
|
* vim: set shiftwidth=4:
|
||||||
|
* vim: set expandtab:
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* indent-tabs-mode: nil
|
||||||
|
* c-indent-level: 4
|
||||||
|
* c-basic-offset: 4
|
||||||
|
* tab-width: 4
|
||||||
|
* End:
|
||||||
|
*/
|
@ -27,7 +27,9 @@
|
|||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
|
|
||||||
#include "xs_internal.h"
|
#include "xs_internal.h"
|
||||||
|
#include "stats_linux.h"
|
||||||
#include "xend_internal.h"
|
#include "xend_internal.h"
|
||||||
|
|
||||||
/* required for dom0_getdomaininfo_t */
|
/* required for dom0_getdomaininfo_t */
|
||||||
@ -1355,74 +1357,23 @@ xenHypervisorSetSchedulerParameters(virDomainPtr domain,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t
|
|
||||||
read_stat (const char *path)
|
|
||||||
{
|
|
||||||
char str[64];
|
|
||||||
int64_t r;
|
|
||||||
int i;
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
fp = fopen (path, "r");
|
|
||||||
if (!fp) return -1;
|
|
||||||
/* stupid GCC warning */ i = fread (str, sizeof str, 1, fp);
|
|
||||||
r = strtoll (str, NULL, 10);
|
|
||||||
fclose (fp);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int64_t
|
|
||||||
read_bd_stat (int device, int domid, const char *str)
|
|
||||||
{
|
|
||||||
char path[PATH_MAX];
|
|
||||||
int64_t r;
|
|
||||||
|
|
||||||
snprintf (path, sizeof path,
|
|
||||||
"/sys/devices/xen-backend/vbd-%d-%d/statistics/%s_req",
|
|
||||||
domid, device, str);
|
|
||||||
r = read_stat (path);
|
|
||||||
if (r >= 0) return r;
|
|
||||||
|
|
||||||
snprintf (path, sizeof path,
|
|
||||||
"/sys/devices/xen-backend/tap-%d-%d/statistics/%s_req",
|
|
||||||
domid, device, str);
|
|
||||||
r = read_stat (path);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Paths have the form "xvd[a-]" and map to paths /sys/devices/xen-backend/
|
|
||||||
* (vbd|tap)-domid-major:minor/statistics/(rd|wr|oo)_req. The major:minor
|
|
||||||
* is in this case fixed as 202*256 + 16*minor where minor is 0 for xvda,
|
|
||||||
* 1 for xvdb and so on.
|
|
||||||
*/
|
|
||||||
int
|
int
|
||||||
xenHypervisorDomainBlockStats (virDomainPtr dom,
|
xenHypervisorDomainBlockStats (virDomainPtr dom,
|
||||||
const char *path,
|
const char *path,
|
||||||
struct _virDomainBlockStats *stats)
|
struct _virDomainBlockStats *stats)
|
||||||
{
|
{
|
||||||
int minor, device;
|
#ifdef __linux__
|
||||||
|
xenUnifiedPrivatePtr priv;
|
||||||
|
|
||||||
if (strlen (path) != 4 ||
|
priv = (xenUnifiedPrivatePtr) dom->conn->privateData;
|
||||||
STRNEQLEN (path, "xvd", 3) ||
|
return xenLinuxDomainBlockStats (priv, dom, path, stats);
|
||||||
(minor = path[3] - 'a') < 0 ||
|
#else
|
||||||
minor > 26) {
|
virXenErrorFunc (VIR_ERR_NO_SUPPORT, __FUNCTION__,
|
||||||
virXenErrorFunc (VIR_ERR_INVALID_ARG, __FUNCTION__,
|
"block statistics not supported on this platform",
|
||||||
"invalid path, should be xvda, xvdb, etc.", 0);
|
dom->id);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
#endif
|
||||||
device = 202 * 256 + minor;
|
|
||||||
|
|
||||||
stats->rd_req = read_bd_stat (device, dom->id, "rd");
|
|
||||||
stats->wr_req = read_bd_stat (device, dom->id, "wr");
|
|
||||||
stats->errs = read_bd_stat (device, dom->id, "oo");
|
|
||||||
|
|
||||||
if (stats->rd_req == -1 && stats->wr_req == -1 && stats->errs == -1) {
|
|
||||||
virXenErrorFunc (VIR_ERR_NO_SUPPORT, __FUNCTION__,
|
|
||||||
"Failed to read any block statistics", dom->id);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Paths have the form vif<domid>.<n> (this interface checks that
|
/* Paths have the form vif<domid>.<n> (this interface checks that
|
||||||
@ -1431,19 +1382,18 @@ xenHypervisorDomainBlockStats (virDomainPtr dom,
|
|||||||
* In future we may allow you to query bridge stats (virbrX or
|
* In future we may allow you to query bridge stats (virbrX or
|
||||||
* xenbrX), but that will probably be through a separate
|
* xenbrX), but that will probably be through a separate
|
||||||
* virNetwork interface, as yet not decided.
|
* virNetwork interface, as yet not decided.
|
||||||
*
|
|
||||||
* On Linux we open /proc/net/dev and look for the device
|
|
||||||
* called vif<domid>.<n>.
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xenHypervisorDomainInterfaceStats (virDomainPtr dom,
|
xenHypervisorDomainInterfaceStats (virDomainPtr dom,
|
||||||
const char *path,
|
const char *path,
|
||||||
struct _virDomainInterfaceStats *stats)
|
struct _virDomainInterfaceStats *stats)
|
||||||
{
|
{
|
||||||
|
#ifdef __linux__
|
||||||
int rqdomid, device;
|
int rqdomid, device;
|
||||||
FILE *fp;
|
|
||||||
char line[256];
|
|
||||||
|
|
||||||
|
/* Verify that the vif requested is one belonging to the current
|
||||||
|
* domain.
|
||||||
|
*/
|
||||||
if (sscanf (path, "vif%d.%d", &rqdomid, &device) != 2) {
|
if (sscanf (path, "vif%d.%d", &rqdomid, &device) != 2) {
|
||||||
virXenErrorFunc (VIR_ERR_INVALID_ARG, __FUNCTION__,
|
virXenErrorFunc (VIR_ERR_INVALID_ARG, __FUNCTION__,
|
||||||
"invalid path, should be vif<domid>.<n>.", 0);
|
"invalid path, should be vif<domid>.<n>.", 0);
|
||||||
@ -1455,56 +1405,12 @@ xenHypervisorDomainInterfaceStats (virDomainPtr dom,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp = fopen ("/proc/net/dev", "r");
|
return linuxDomainInterfaceStats (dom->conn, path, stats);
|
||||||
if (!fp) {
|
#else
|
||||||
virXenErrorFunc (VIR_ERR_NO_SUPPORT, __FUNCTION__,
|
|
||||||
"/proc/net/dev", errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
while (fgets (line, sizeof line, fp)) {
|
|
||||||
int domid, port;
|
|
||||||
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;
|
|
||||||
|
|
||||||
/* 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 (line, "vif%d.%d: %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld",
|
|
||||||
&domid, &port,
|
|
||||||
&tx_bytes, &tx_packets, &tx_errs, &tx_drop,
|
|
||||||
&dummy, &dummy, &dummy, &dummy,
|
|
||||||
&rx_bytes, &rx_packets, &rx_errs, &rx_drop,
|
|
||||||
&dummy, &dummy, &dummy, &dummy) != 18)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (domid == dom->id && port == device) {
|
|
||||||
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;
|
|
||||||
fclose (fp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose (fp);
|
|
||||||
|
|
||||||
virXenErrorFunc (VIR_ERR_NO_SUPPORT, __FUNCTION__,
|
virXenErrorFunc (VIR_ERR_NO_SUPPORT, __FUNCTION__,
|
||||||
"/proc/net/dev: Interface not found", 0);
|
"/proc/net/dev: Interface not found", 0);
|
||||||
return -1;
|
return -1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user