diff --git a/tools/xenstat/libxenstat/src/xenstat_linux.c b/tools/xenstat/libxenstat/src/xenstat_linux.c index 2d442fb..5d3ecdd 100644 --- a/tools/xenstat/libxenstat/src/xenstat_linux.c +++ b/tools/xenstat/libxenstat/src/xenstat_linux.c @@ -28,6 +28,7 @@ #include #include #include +#include #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; }