All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michal Novotny <minovotn@redhat.com>
To: "'xen-devel@lists.xensource.com'" <xen-devel@lists.xensource.com>
Subject: [PATCH] Linux dom0 statistics for case we use network bonding
Date: Mon, 30 Nov 2009 16:58:13 +0100	[thread overview]
Message-ID: <4B13EB95.5010307@redhat.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 384 bytes --]

Hi,
I've created a patch that alters dom0 statistics (if empty like in case 
of network bonding) and puts network bridge statistics instead. It's 
been tested with network bonding both enabled and disabled and also by 
creating a standalone network bridge without bonding... It was working 
fine in all my tests...

Thanks,
Michal

Signed-off-by: Michal Novotny <minovotn@redhat.com>

[-- Attachment #2: xen-xenstat-dom0-stats-with-bonding-interface.patch --]
[-- Type: text/x-patch, Size: 10656 bytes --]

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 <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;
 }

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

                 reply	other threads:[~2009-11-30 15:58 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4B13EB95.5010307@redhat.com \
    --to=minovotn@redhat.com \
    --cc=xen-devel@lists.xensource.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.