aboutsummaryrefslogtreecommitdiffstats
path: root/tools/xenstat/libxenstat/src/xenstat_linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/xenstat/libxenstat/src/xenstat_linux.c')
-rw-r--r--tools/xenstat/libxenstat/src/xenstat_linux.c260
1 files changed, 227 insertions, 33 deletions
diff --git a/tools/xenstat/libxenstat/src/xenstat_linux.c b/tools/xenstat/libxenstat/src/xenstat_linux.c
index a390ac8ed7..4f22b593aa 100644
--- a/tools/xenstat/libxenstat/src/xenstat_linux.c
+++ b/tools/xenstat/libxenstat/src/xenstat_linux.c
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <regex.h>
#include "xenstat_priv.h"
@@ -61,9 +62,185 @@ static const char PROCNETDEV_HEADER[] =
" face |bytes packets errs drop fifo frame compressed multicast|"
"bytes packets errs drop fifo colls carrier compressed\n";
+/* We need to get the name of the bridge interface for use with bonding interfaces */
+/* Use excludeName parameter to avoid adding bridges we don't care about, eg. virbr0 */
+char *getBridge(char *excludeName)
+{
+ struct dirent *de;
+ DIR *d;
+
+ char tmp[256] = { 0 }, *bridge;
+
+ bridge = (char *)malloc(16 * sizeof(char));
+
+ d = opendir("/sys/class/net");
+ while ((de = readdir(d)) != NULL) {
+ if ((strlen(de->d_name) > 0) && (de->d_name[0] != '.')
+ && (strstr(de->d_name, excludeName) == NULL)) {
+ sprintf(tmp, "/sys/class/net/%s/bridge", de->d_name);
+
+ if (access(tmp, F_OK) == 0)
+ bridge = de->d_name;
+ }
+ }
+ closedir(d);
+
+ return bridge;
+}
+
+/* parseNetLine provides regular expression based parsing for lines from /proc/net/dev, all the */
+/* information are parsed but not all are used in our case, ie. for xenstat */
+int parseNetDevLine(char *line, char *iface, unsigned long long *rxBytes, unsigned long long *rxPackets,
+ unsigned long long *rxErrs, unsigned long long *rxDrops, unsigned long long *rxFifo,
+ unsigned long long *rxFrames, unsigned long long *rxComp, unsigned long long *rxMcast,
+ unsigned long long *txBytes, unsigned long long *txPackets, unsigned long long *txErrs,
+ unsigned long long *txDrops, unsigned long long *txFifo, unsigned long long *txColls,
+ unsigned long long *txCarrier, unsigned long long *txComp)
+{
+ /* Temporary/helper variables */
+ int ret;
+ char *tmp;
+ int i = 0, x = 0, col = 0;
+ regex_t r;
+ regmatch_t matches[19];
+ int num = 19;
+
+ /* Regular exception to parse all the information from /proc/net/dev line */
+ char *regex = "([^:]*):([^ ]*)[ ]*([^ ]*)[ ]*([^ ]*)[ ]*([^ ]*)[ ]*([^ ]*)[ ]*([^ ]*)"
+ "[ ]*([^ ]*)[ ]*([^ ]*)[ ]*([^ ]*)[ ]*([^ ]*)[ ]*([^ ]*)[ ]*([^ ]*)[ ]*"
+ "([^ ]*)[ ]*([^ ]*)[ ]*([^ ]*)[ ]*([^ ]*)[ ]*([^ ]*)";
+
+ /* Initialize all variables called has passed as non-NULL to zeros */
+ if (iface != NULL)
+ memset(iface, 0, sizeof(iface));
+ if (rxBytes != NULL)
+ *rxBytes = 0;
+ if (rxPackets != NULL)
+ *rxPackets = 0;
+ if (rxErrs != NULL)
+ *rxErrs = 0;
+ if (rxDrops != NULL)
+ *rxDrops = 0;
+ if (rxFifo != NULL)
+ *rxFifo = 0;
+ if (rxFrames != NULL)
+ *rxFrames = 0;
+ if (rxPackets != NULL)
+ *rxPackets = 0;
+ if (rxComp != NULL)
+ *rxComp = 0;
+ if (txBytes != NULL)
+ *txBytes = 0;
+ if (txPackets != NULL)
+ *txPackets = 0;
+ if (txErrs != NULL)
+ *txErrs = 0;
+ if (txDrops != NULL)
+ *txDrops = 0;
+ if (txFifo != NULL)
+ *txFifo = 0;
+ if (txColls != NULL)
+ *txColls = 0;
+ if (txCarrier != NULL)
+ *txCarrier = 0;
+ if (txComp != NULL)
+ *txComp = 0;
+
+ if ((ret = regcomp(&r, regex, REG_EXTENDED))) {
+ regfree(&r);
+ return ret;
+ }
+
+ tmp = (char *)malloc( sizeof(char) );
+ if (regexec (&r, line, num, matches, REG_EXTENDED) == 0){
+ for (i = 1; i < num; i++) {
+ /* The expression matches are empty sometimes so we need to check it first */
+ if (matches[i].rm_eo - matches[i].rm_so > 0) {
+ /* Col variable contains current id of non-empty match */
+ col++;
+ tmp = (char *)realloc(tmp, (matches[i].rm_eo - matches[i].rm_so + 1) * sizeof(char));
+ for (x = matches[i].rm_so; x < matches[i].rm_eo; x++)
+ tmp[x - matches[i].rm_so] = line[x];
+
+ /* We populate all the fields from /proc/net/dev line */
+ if (i > 1) {
+ unsigned long long ullTmp = strtoull(tmp, NULL, 10);
+
+ switch (col) {
+ case 2: if (rxBytes != NULL)
+ *rxBytes = ullTmp;
+ break;
+ case 3: if (rxPackets != NULL)
+ *rxPackets = ullTmp;
+ break;
+ case 4: if (rxErrs != NULL)
+ *rxErrs = ullTmp;
+ break;
+ case 5: if (rxDrops != NULL)
+ *rxDrops = ullTmp;
+ break;
+ case 6: if (rxFifo != NULL)
+ *rxFifo = ullTmp;
+ break;
+ case 7: if (rxFrames != NULL)
+ *rxFrames = ullTmp;
+ break;
+ case 8: if (rxComp != NULL)
+ *rxComp = ullTmp;
+ break;
+ case 9: if (rxMcast != NULL)
+ *rxMcast = ullTmp;
+ break;
+ case 10: if (txBytes != NULL)
+ *txBytes = ullTmp;
+ break;
+ case 11: if (txPackets != NULL)
+ *txPackets = ullTmp;
+ break;
+ case 12: if (txErrs != NULL)
+ *txErrs = ullTmp;
+ case 13: if (txDrops != NULL)
+ *txDrops = ullTmp;
+ break;
+ case 14: if (txFifo != NULL)
+ *txFifo = ullTmp;
+ break;
+ case 15: if (txColls != NULL)
+ *txColls = ullTmp;
+ break;
+ case 16: if (txCarrier != NULL)
+ *txCarrier = ullTmp;
+ break;
+ case 17: if (txComp != NULL)
+ *txComp = ullTmp;
+ break;
+ }
+ }
+ else
+ /* There were errors when parsing this directly in RE. strpbrk() helps */
+ if (iface != NULL)
+ strcpy(iface, strpbrk(tmp, "abcdefghijklmnopqrstvuwxyz0123456789"));
+
+ memset(tmp, 0, matches[i].rm_eo - matches[i].rm_so);
+ }
+ }
+ }
+
+ free(tmp);
+ regfree(&r);
+
+ return 0;
+}
+
/* Collect information about networks */
int xenstat_collect_networks(xenstat_node * node)
{
+ /* Helper variables for parseNetDevLine() function defined above */
+ int i;
+ char line[512] = { 0 }, iface[16] = { 0 }, devBridge[16] = { 0 }, devNoBridge[16] = { 0 };
+ unsigned long long rxBytes, rxPackets, rxErrs, rxDrops, rxFifo, rxFrames, rxComp, rxMcast;
+ unsigned long long txBytes, txPackets, txErrs, txDrops, txFifo, txColls, txCarrier, txComp;
+
struct priv_data *priv = get_priv_data(node->handle);
if (priv == NULL) {
@@ -98,43 +275,59 @@ int xenstat_collect_networks(xenstat_node * node)
/* FIXME: optimize this */
fseek(priv->procnetdev, sizeof(PROCNETDEV_HEADER) - 1,
SEEK_SET);
- while (1) {
- xenstat_domain *domain;
- xenstat_network net;
- unsigned int domid;
- int ret = fscanf(priv->procnetdev,
- "vif%u.%u:%llu%llu%llu%llu%*u%*u%*u%*u"
- "%llu%llu%llu%llu%*u%*u%*u%*u\n",
- &domid, &net.id,
- &net.tbytes, &net.tpackets, &net.terrs,
- &net.tdrop,
- &net.rbytes, &net.rpackets, &net.rerrs,
- &net.rdrop);
- if (ret == EOF)
- break;
- if (ret != 10) {
- unsigned int c;
- do {
- c = fgetc(priv->procnetdev);
- } while (c != '\n' && c != EOF);
- if (c == EOF)
- break;
- continue;
- }
- /* FIXME: this does a search for the domid */
- domain = xenstat_node_domain(node, domid);
- if (domain == NULL) {
+ /* We get the bridge devices for use with bonding interface to get bonding interface stats */
+ snprintf(devBridge, 16, "%s", getBridge("vir"));
+ snprintf(devNoBridge, 16, "p%s", devBridge);
+
+ while (fgets(line, 512, priv->procnetdev)) {
+ xenstat_domain *domain;
+ xenstat_network net;
+ unsigned int domid;
+
+ parseNetDevLine(line, iface, &rxBytes, &rxPackets, &rxErrs, &rxDrops, &rxFifo, &rxFrames, &rxComp,
+ &rxMcast, &txBytes, &txPackets, &txErrs, &txDrops, &txFifo, &txColls, &txCarrier, &txComp);
+
+ /* If the device parsed is network bridge and both tx & rx packets are zero, we are most */
+ /* likely using bonding so we alter the configuration for dom0 to have bridge stats */
+ if ((strstr(iface, devBridge) != NULL) && (strstr(iface, devNoBridge) == NULL)) {
+ domain = xenstat_node_domain(node, 0);
+ for (i = 0; i < domain->num_networks; i++) {
+ if ((domain->networks[i].id == 0) && (domain->networks[i].tbytes == 0)
+ && (domain->networks[i].rbytes == 0)) {
+ domain->networks[i].tbytes = txBytes;
+ domain->networks[i].tpackets = txPackets;
+ domain->networks[i].rbytes = rxBytes;
+ domain->networks[i].rpackets = rxPackets;
+ }
+ }
+ }
+ else /* Otherwise we need to preserve old behaviour */
+ if (strstr(iface, "vif") != NULL) {
+ sscanf(iface, "vif%u.%u", &domid, &net.id);
+
+ net.tbytes = txBytes;
+ net.tpackets = txPackets;
+ net.terrs = txErrs;
+ net.tdrop = txDrops;
+ net.rbytes = rxBytes;
+ net.rpackets = rxPackets;
+ net.rerrs = rxErrs;
+ net.rdrop = rxDrops;
+
+ /* FIXME: this does a search for the domid */
+ domain = xenstat_node_domain(node, domid);
+ if (domain == NULL) {
fprintf(stderr,
"Found interface vif%u.%u but domain %u"
" does not exist.\n", domid, net.id,
domid);
continue;
- }
- if (domain->networks == NULL) {
+ }
+ if (domain->networks == NULL) {
domain->num_networks = 1;
domain->networks = malloc(sizeof(xenstat_network));
- } else {
+ } else {
struct xenstat_network *tmp;
domain->num_networks++;
tmp = realloc(domain->networks,
@@ -143,11 +336,12 @@ int xenstat_collect_networks(xenstat_node * node)
if (tmp == NULL)
free(domain->networks);
domain->networks = tmp;
- }
- if (domain->networks == NULL)
+ }
+ if (domain->networks == NULL)
return 0;
- domain->networks[domain->num_networks - 1] = net;
- }
+ domain->networks[domain->num_networks - 1] = net;
+ }
+ }
return 1;
}