Please find below a patch making proc_run report non-zeron values and
adding all the meterics provided by Linux.  I've tested them on my
laptop runnng 5.1-CURRENT and a 4.9-PRERELEASE machine.  This patch
brings the FreeBSD port to feature parity with Linux.  FreeBSD users,
please test/review this.  I'd like to commit it sometime soon.

Thanks,
Brooks

Index: configure.in
===================================================================
RCS file: /cvsroot/ganglia/monitor-core/configure.in,v
retrieving revision 1.32
diff -u -p -u -r1.32 configure.in
--- configure.in        6 May 2003 17:50:21 -0000       1.32
+++ configure.in        6 Oct 2003 23:30:19 -0000
@@ -358,13 +358,10 @@ dnl
                   CFLAGS="$CFLAGS -D__STDC__ -D_POSIX_C_SOURCE=199506L 
-DHAVE_STRERROR"
                fi 
                 AC_DEFINE(SOLARIS,1,SOLARIS);;
-dnl
-dnl Why did BSD decide to do this?  Why not have a separate pthreads library?
-dnl
 *freebsd*)      metric_source="freebsd.c" 
                 CFLAGS="-pthread $CFLAGS -D_REENTRANT" 
                AC_DEFINE(SUPPORT_GEXEC, 0, SUPPORT_GEXEC)
-                AC_DEFINE(BSD,1,BSD);; 
+                AC_DEFINE(FREEBSD, 1, FREEBSD);; 
 *cygwin*)              metric_source="cygwin.c" 
                AC_DEFINE(CYGWIN,1,CYGWIN)
 esac
Index: gmond/key_metrics.h
===================================================================
RCS file: /cvsroot/ganglia/monitor-core/gmond/key_metrics.h,v
retrieving revision 1.11
diff -u -p -u -r1.11 key_metrics.h
--- gmond/key_metrics.h 7 Mar 2003 20:38:31 -0000       1.11
+++ gmond/key_metrics.h 6 Oct 2003 23:30:20 -0000
@@ -69,6 +69,15 @@ enum {
    cpu_avm,
    cpu_vm,
 #endif
+#ifdef FREEBSD
+   bytes_in,
+   bytes_out,
+   pkts_in,
+   pkts_out,
+   disk_total,
+   disk_free,
+   part_max_used,
+#endif
    num_key_metrics
 }  key_metrics;
 #endif
Index: gmond/metric.h
===================================================================
RCS file: /cvsroot/ganglia/monitor-core/gmond/metric.h,v
retrieving revision 1.13
diff -u -p -u -r1.13 metric.h
--- gmond/metric.h      14 Jul 2003 21:52:58 -0000      1.13
+++ gmond/metric.h      6 Oct 2003 23:30:20 -0000
@@ -88,6 +88,18 @@ extern g_val_t mem_avm_func(void);
 
 #endif
 
+#ifdef FREEBSD
+
+extern g_val_t bytes_in_func(void);
+extern g_val_t bytes_out_func(void);
+extern g_val_t pkts_in_func(void);
+extern g_val_t pkts_out_func(void);
+extern g_val_t disk_total_func(void);
+extern g_val_t disk_free_func(void);
+extern g_val_t part_max_used_func(void);
+
+#endif
+
 #define INIT 0, 0, {0}, {0}
 #define KEY(NAME) { #NAME, NAME ##_func, INIT
 
@@ -182,7 +194,8 @@ KEY(bytes_in),   4096, 30,   40,  200,  
 KEY(pkts_in), 256, 30,   40,  200,  300, g_float, "packets/sec", "%.2f" },
 KEY(pkts_out),   256, 30,   40,  200,  300, g_float, "packets/sec", "%.2f" },
 
-/* The amount of disk space could change - hot-swap, mounts, etc. check: 
30-60min. */
+/*
+ * The amount of disk space could change - hot-swap, mounts, etc. check: 
30-60min. */
 KEY(disk_total), 1, 1800, 3600, 900, 1200, g_double, "GB", "%.3f" },
 KEY(disk_free), 1, 30, 40, 120, 180, g_double, "GB", "%.3f" },
 KEY(part_max_used), 1, 30, 40, 120, 180, g_float, "%", "%.1f" }
@@ -198,6 +211,30 @@ KEY(mem_arm),   1024,  30,   40,  120,  
 KEY(mem_rm),   1024,  30,   40,  120,  180, g_uint32, "KB", "%u" },
 KEY(mem_avm),   1024,  30,   40,  120,  180, g_uint32, "KB", "%u" },
 KEY(mem_vm),   1024,  30,   40,  120,  180, g_uint32, "KB", "%u" }
+
+#endif
+
+#ifdef FREEBSD
+
+,
+/*
+ * (sacerdoti) Experiments have shown gmon resting bandwidth is around
+ * 2KB/s for a 128-node cluster. We set the value thresh of these
+ * metrics to double that.
+ *
+ */
+KEY(bytes_out),  4096, 30,   40,  200,  300, g_float, "bytes/sec", "%.2f" },
+KEY(bytes_in),   4096, 30,   40,  200,  300, g_float, "bytes/sec", "%.2f" },
+KEY(pkts_in), 256, 30,   40,  200,  300, g_float, "packets/sec", "%.2f" },
+KEY(pkts_out),   256, 30,   40,  200,  300, g_float, "packets/sec", "%.2f" },
+
+/*
+ * The amount of disk space could change - hot-swap, mounts, etc.
+ * check: 30-60min.
+ */
+KEY(disk_total), 1, 1800, 3600, 900, 1200, g_double, "GB", "%.3f" },
+KEY(disk_free), 1, 30, 40, 120, 180, g_double, "GB", "%.3f" },
+KEY(part_max_used), 1, 30, 40, 120, 180, g_float, "%", "%.1f" }
 
 #endif
 };
Index: gmond/machines/freebsd.c
===================================================================
RCS file: /cvsroot/ganglia/monitor-core/gmond/machines/freebsd.c,v
retrieving revision 1.4
diff -u -p -u -r1.4 freebsd.c
--- gmond/machines/freebsd.c    23 Jul 2003 02:05:55 -0000      1.4
+++ gmond/machines/freebsd.c    6 Oct 2003 23:30:21 -0000
@@ -9,9 +9,11 @@
  */
 
 #include <kvm.h>
-#include <fcntl.h>
+
 #include <sys/param.h> 
+#include <sys/mount.h>
 #include <sys/sysctl.h>
+#include <sys/time.h>
 #include <sys/user.h>
 #if __FreeBSD_version < 500101
 #include <sys/dkstat.h>
@@ -20,12 +22,35 @@
 #endif
 #include <sys/stat.h>
 #include <vm/vm_param.h>
+
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+
 #include <unistd.h>
+#include <err.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <paths.h>
+
+#include "dnet.h"
 #include "ganglia.h"
 #include "metric_typedefs.h"
 
 #define MIB_SWAPINFO_SIZE 3
 
+#ifndef MIN_NET_POLL_INTERVAL
+#define MIN_NET_POLL_INTERVAL 0.5
+#endif
+
+#ifndef UINT64_MAX
+#define UINT64_MAX     ULLONG_MAX
+#endif
+
+#define timertod(tvp) \
+    ((double)(tvp)->tv_sec + (double)(tvp)->tv_usec/(1000*1000))
+
 #ifndef XSWDEV_VERSION
 #define XSWDEV_VERSION  1
 struct xswdev {
@@ -37,14 +62,32 @@ struct xswdev {
 };
 #endif
 
+struct traffic {
+       uint64_t in_bytes;
+       uint64_t out_bytes;
+       uint64_t in_pkts;
+       uint64_t out_pkts;
+};
+
+static void get_netbw(double *, double *, double *, double *);
+static uint64_t counterdiff(uint64_t, uint64_t, uint64_t, uint64_t);
+
+
+static char     *makenetvfslist(void);
+static size_t    regetmntinfo(struct statfs **, long, const char **);
+static int       checkvfsname(const char *, const char **);
+static const char **makevfslist(char *);
+static float     find_disk_space(double *, double *);
+
 static int use_vm_swap_info = 0;
 static int mibswap[MIB_SWAPINFO_SIZE];
 static size_t mibswap_size;
 static kvm_t *kd = NULL;
 static int pagesize;
+static int       skipvfs;
 
 /* Function prototypes */
-long percentages(int cnt, int *out, register long *new,
+static long percentages(int cnt, int *out, register long *new,
                           register long *old, long *diffs);
  
 /*
@@ -64,10 +107,25 @@ metric_init(void)
    if (sysctlnametomib("vm.swap_info", mibswap, &mibswap_size) == -1) {
       kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "metric_init()");
    } else {
+      /*
+       * Versions of FreeBSD with the swap mib generally have a version
+       * of libkvm that doesn't need root for simple proc access so we
+       * just open /dev/null to give us a working handle here.  This is
+       * bogus, but only a few pre-release versions of 5.0 are
+       * affected by the bogosity and people running those should
+       * upgrade.
+       */
+      kd = kvm_open(_PATH_DEVNULL, NULL, NULL, O_RDONLY, "metric_init()");
       use_vm_swap_info = 1;
    }
    pagesize = getpagesize();
 
+   /*
+    * Call get_netbw once to initalize the counters.
+    */
+
+   get_netbw(NULL, NULL, NULL, NULL);
+
    val.int32 = SYNAPSE_SUCCESS;
    return val;
 }
@@ -124,7 +182,7 @@ swap_total_func ( void )
    g_val_t val;
    struct kvm_swap swap[1];
    struct xswdev xsw;
-   size_t mibsize, size;
+   size_t size;
    int totswap, n;
    val.uint32 = 0;
    totswap = 0;
@@ -366,9 +424,41 @@ proc_total_func ( void )
 g_val_t
 proc_run_func( void )
 {
+   struct kinfo_proc *kp;
+   int i;
+   int state;
+   int nentries;
+   int what = KERN_PROC_ALL;
    g_val_t val;
 
    val.uint32 = 0;
+
+   if (kd == NULL)
+      goto output;
+#ifdef KERN_PROC_NOTHREADS
+   what |= KERN_PROC_NOTHREADS
+#endif
+   if ((kp = kvm_getprocs(kd, what, 0, &nentries)) == 0 || nentries < 0)
+      goto output;
+
+   for (i = 0; i < nentries; kp++, i++) {
+#ifdef KINFO_PROC_SIZE
+      state = kp->ki_stat;
+#else
+      state = kp->kp_proc.p_stat;
+#endif
+      switch(state) {
+        case SRUN:
+        case SIDL:
+               val.uint32++;
+               break;
+      }
+   }
+
+   if (val.uint32 > 0)
+       val.uint32--;
+
+output:
    return val;
 }
 
@@ -461,7 +551,6 @@ swap_free_func ( void )
    return val;
 }
 
-#include "dnet.h"
 
 static int
 find_mtu(const struct intf_entry *entry, void *arg)
@@ -509,8 +598,8 @@ mtu_func ( void )
  * $FreeBSD: src/usr.bin/top/machine.c,v 1.29.2.2 2001/07/31 20:27:05 tmm Exp $
  */
 
-long percentages(int cnt, int *out, register long *new, 
-                          register long *old, long *diffs)  {
+static long percentages(int cnt, int *out, register long *new, 
+                        register long *old, long *diffs)  {
 
     register int i;
     register long change;
@@ -549,3 +638,563 @@ long percentages(int cnt, int *out, regi
     return(total_change);
 }
 
+g_val_t
+pkts_in_func ( void )
+{
+   double in_pkts;
+   g_val_t val;
+
+   get_netbw(NULL, NULL, &in_pkts, NULL);
+
+   val.f = (float)in_pkts;
+   return val;
+}
+
+g_val_t
+pkts_out_func ( void )
+{
+   double out_pkts;
+   g_val_t val;
+
+   get_netbw(NULL, NULL, NULL, &out_pkts);
+
+   val.f = (float)out_pkts;
+   return val;
+}
+
+g_val_t
+bytes_out_func ( void )
+{
+   double out_bytes;
+   g_val_t val;
+
+   get_netbw(NULL, &out_bytes, NULL, NULL);
+
+   val.f = (float)out_bytes;
+   return val;
+}
+
+g_val_t
+bytes_in_func ( void )
+{
+   double in_bytes;
+   g_val_t val;
+
+   get_netbw(&in_bytes, NULL, NULL, NULL);
+
+   val.f = (float)in_bytes;
+   return val;
+}
+
+/*
+ * Disk space reporting functions from Linux code.  find_disk_space()
+ * body derived from FreeBSD df and mount code.
+ */
+
+g_val_t
+disk_free_func( void )
+{
+   double total_free=0.0;
+   double total_size=0.0;
+   g_val_t val;
+
+   find_disk_space(&total_size, &total_free);
+
+   val.d = total_free;
+   return val;
+}
+
+g_val_t
+disk_total_func( void )
+{
+   double total_free=0.0;
+   double total_size=0.0;
+   g_val_t val;
+
+   find_disk_space(&total_size, &total_free);
+
+   val.d = total_size;
+   return val;
+}
+
+g_val_t
+part_max_used_func( void )
+{
+   double total_free=0.0;
+   double total_size=0.0;
+   float most_full;
+   g_val_t val;
+
+   most_full = find_disk_space(&total_size, &total_free);
+
+   val.f = most_full;
+   return val;
+}
+
+
+/*
+ * Copyright (c) 1980, 1983, 1990, 1993, 1994, 1995
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *
+ * NOTE: The copyright of UC Berkeley's Berkeley Software Distribution
+ * ("BSD") source has been updated.  The copyright addendum may be found
+ * at ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change.
+ */
+
+
+
+static float
+find_disk_space(double *total, double *tot_avail)
+{
+       struct statfs *mntbuf;
+       const char *fstype;
+       const char **vfslist;
+       size_t i, mntsize;
+       size_t used, availblks;
+       const double reported_units = 1e9;
+       double toru;
+       float pct;
+       float most_full = 0.0;
+
+       *total = 0.0;
+       *tot_avail = 0.0;
+
+       fstype = "ufs";
+
+       vfslist = makevfslist(makenetvfslist());
+
+       mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
+       mntsize = regetmntinfo(&mntbuf, mntsize, vfslist);
+       for (i = 0; i < mntsize; i++) {
+               if ((mntbuf[i].f_flags & MNT_IGNORE) == 0) {
+                       used = mntbuf[i].f_blocks - mntbuf[i].f_bfree;
+                       availblks = mntbuf[i].f_bavail + used;
+                       pct = (availblks == 0 ? 100.0 :
+                           (double)used / (double)availblks * 100.0);
+                       if (pct > most_full)
+                               most_full = pct;
+
+                       toru = reported_units/mntbuf[i].f_bsize;
+                       *total += mntbuf[i].f_blocks / toru;
+                       *tot_avail += mntbuf[i].f_bavail / toru;
+               }
+       }
+
+       return most_full;
+}
+
+/*
+ * Make a pass over the file system info in ``mntbuf'' filtering out
+ * file system types not in vfslist and possibly re-stating to get
+ * current (not cached) info.  Returns the new count of valid statfs bufs.
+ */
+static size_t
+regetmntinfo(struct statfs **mntbufp, long mntsize, const char **vfslist)
+{
+       int i, j;
+       struct statfs *mntbuf;
+
+       if (vfslist == NULL)
+               return (getmntinfo(mntbufp, MNT_WAIT));
+
+       mntbuf = *mntbufp;
+       for (j = 0, i = 0; i < mntsize; i++) {
+               if (checkvfsname(mntbuf[i].f_fstypename, vfslist))
+                       continue;
+               (void)statfs(mntbuf[i].f_mntonname,&mntbuf[j]);
+               j++;
+       }
+       return (j);
+}
+
+static int
+checkvfsname(vfsname, vfslist)
+       const char *vfsname;
+       const char **vfslist;
+{
+
+       if (vfslist == NULL)
+               return (0);
+       while (*vfslist != NULL) {
+               if (strcmp(vfsname, *vfslist) == 0)
+                       return (skipvfs);
+               ++vfslist;
+       }
+       return (!skipvfs);
+}
+
+static const char **
+makevfslist(fslist)
+       char *fslist;
+{
+       const char **av;
+       int i;
+       char *nextcp;
+
+       if (fslist == NULL)
+               return (NULL);
+       if (fslist[0] == 'n' && fslist[1] == 'o') {
+               fslist += 2;
+               skipvfs = 1;
+       }
+       for (i = 0, nextcp = fslist; *nextcp; nextcp++)
+               if (*nextcp == ',')
+                       i++;
+       if ((av = malloc((size_t)(i + 2) * sizeof(char *))) == NULL) {
+               warnx("malloc failed");
+               return (NULL);
+       }
+       nextcp = fslist;
+       i = 0;
+       av[i++] = nextcp;
+       while ((nextcp = strchr(nextcp, ',')) != NULL) {
+               *nextcp++ = '\0';
+               av[i++] = nextcp;
+       }
+       av[i++] = NULL;
+       return (av);
+}
+
+static char *
+makenetvfslist(void)
+{
+#if __FreeBSD_version > 500000
+       char *str, *strptr, **listptr;
+       struct xvfsconf *xvfsp, *keep_xvfsp;
+       size_t buflen;
+       int cnt, i, maxvfsconf;
+
+       if (sysctlbyname("vfs.conflist", NULL, &buflen, NULL, 0) < 0) {
+               warn("sysctl(vfs.conflist)");
+               return (NULL);
+       }
+       xvfsp = malloc(buflen);
+       if (xvfsp == NULL) {
+               warnx("malloc failed");
+               return (NULL);
+       }
+       keep_xvfsp = xvfsp;
+       if (sysctlbyname("vfs.conflist", xvfsp, &buflen, NULL, 0) < 0) {
+               warn("sysctl(vfs.conflist)");
+               free(keep_xvfsp);
+               return (NULL);
+       }
+       maxvfsconf = buflen / sizeof(struct xvfsconf);
+
+       if ((listptr = malloc(sizeof(char*) * maxvfsconf)) == NULL) {
+               warnx("malloc failed");
+               free(keep_xvfsp);
+               return (NULL);
+       }
+
+       for (cnt = 0, i = 0; i < maxvfsconf; i++) {
+               if (xvfsp->vfc_flags & 
(VFCF_NETWORK|VFCF_SYNTHETIC|VFCF_LOOPBACK)) {
+                       listptr[cnt++] = strdup(xvfsp->vfc_name);
+                       if (listptr[cnt-1] == NULL) {
+                               warnx("malloc failed");
+                               free(listptr);
+                               free(keep_xvfsp);
+                               return (NULL);
+                       }
+               }
+               xvfsp++;
+       }
+
+       if (cnt == 0 ||
+           (str = malloc(sizeof(char) * (32 * cnt + cnt + 2))) == NULL) {
+               if (cnt > 0)
+                       warnx("malloc failed");
+               free(listptr);
+               free(keep_xvfsp);
+               return (NULL);
+       }
+
+       *str = 'n'; *(str + 1) = 'o';
+       for (i = 0, strptr = str + 2; i < cnt; i++, strptr++) {
+               strncpy(strptr, listptr[i], 32);
+               strptr += strlen(listptr[i]);
+               *strptr = ',';
+               free(listptr[i]);
+       }
+       *(--strptr) = NULL;
+
+       free(keep_xvfsp);
+#else
+       char *str, *strptr, **listptr;
+       int mib[3], maxvfsconf, cnt=0, i;
+       size_t miblen;
+       struct ovfsconf *ptr;
+
+       mib[0] = CTL_VFS; mib[1] = VFS_GENERIC; mib[2] = VFS_MAXTYPENUM;
+       miblen=sizeof(maxvfsconf);
+       if (sysctl(mib, (unsigned int)(sizeof(mib) / sizeof(mib[0])),
+           &maxvfsconf, &miblen, NULL, 0)) {
+               warnx("sysctl failed");
+               return (NULL);
+       }
+
+       if ((listptr = malloc(sizeof(char*) * maxvfsconf)) == NULL) {
+               warnx("malloc failed");
+               return (NULL);
+       }
+
+       for (ptr = getvfsent(); ptr; ptr = getvfsent())
+               if (ptr->vfc_flags & 
(VFCF_NETWORK|VFCF_SYNTHETIC|VFCF_LOOPBACK)) {
+                       listptr[cnt++] = strdup(ptr->vfc_name);
+                       if (listptr[cnt-1] == NULL) {
+                               warnx("malloc failed");
+                               return (NULL);
+                       }
+               }
+
+       if (cnt == 0 ||
+           (str = malloc(sizeof(char) * (32 * cnt + cnt + 2))) == NULL) {
+               if (cnt > 0)
+                       warnx("malloc failed");
+               free(listptr);
+               return (NULL);
+       }
+
+       *str = 'n'; *(str + 1) = 'o';
+       for (i = 0, strptr = str + 2; i < cnt; i++, strptr++) {
+               strncpy(strptr, listptr[i], 32);
+               strptr += strlen(listptr[i]);
+               *strptr = ',';
+               free(listptr[i]);
+       }
+       *(--strptr) = NULL;
+
+#endif
+       free(listptr);
+       return (str);
+
+}
+
+static void
+get_netbw(double *in_bytes, double *out_bytes,
+    double *in_pkts, double *out_pkts)
+{
+#ifdef NETBW_DEBUG
+       char            name[IFNAMSIZ];
+#endif
+       struct          if_msghdr *ifm, *nextifm;
+       struct          sockaddr_dl *sdl;
+       char            *buf, *lim, *next;
+       size_t          needed;
+       int             mib[6];
+       int             i;
+       int             index;
+       static double   ibytes, obytes, ipkts, opkts;
+       struct timeval  this_time;
+       struct timeval  time_diff;
+       struct traffic  traffic;
+       static struct timeval last_time = {0,0};
+       static int      indexes = 0;
+       static int      *seen = NULL;
+       static struct traffic *lastcount = NULL;
+       static double   o_ibytes, o_obytes, o_ipkts, o_opkts;
+
+       ibytes = obytes = ipkts = opkts = 0.0;
+
+       mib[0] = CTL_NET;
+       mib[1] = PF_ROUTE;
+       mib[2] = 0;
+       mib[3] = 0;                     /* address family */
+       mib[4] = NET_RT_IFLIST;
+       mib[5] = 0;             /* interface index */
+
+       gettimeofday(&this_time, NULL);
+       timersub(&this_time, &last_time, &time_diff);
+       if (timertod(&time_diff) < MIN_NET_POLL_INTERVAL) {
+               goto output;
+       }
+
+
+       if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+               errx(1, "iflist-sysctl-estimate");
+       if ((buf = malloc(needed)) == NULL)
+               errx(1, "malloc");
+       if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+               errx(1, "actual retrieval of interface table");
+       lim = buf + needed;
+
+       next = buf;
+       while (next < lim) {
+
+               ifm = (struct if_msghdr *)next;
+               
+               if (ifm->ifm_type == RTM_IFINFO) {
+                       sdl = (struct sockaddr_dl *)(ifm + 1);
+               } else {
+                       fprintf(stderr, "out of sync parsing NET_RT_IFLIST\n");
+                       fprintf(stderr, "expected %d, got %d\n", RTM_IFINFO,
+                               ifm->ifm_type);
+                       fprintf(stderr, "msglen = %d\n", ifm->ifm_msglen);
+                       fprintf(stderr, "buf:%p, next:%p, lim:%p\n", buf, next,
+                               lim);
+                       exit (1);
+               }
+
+               next += ifm->ifm_msglen;
+               while (next < lim) {
+                       nextifm = (struct if_msghdr *)next;
+
+                       if (nextifm->ifm_type != RTM_NEWADDR)
+                               break;
+
+                       next += nextifm->ifm_msglen;
+               }
+
+               if ((ifm->ifm_flags & IFF_LOOPBACK) || 
+                   !(ifm->ifm_flags & IFF_UP))
+                       continue;
+
+               index = ifm->ifm_index;
+
+               /* If we don't have a previous value yet, make a slot. */
+               if (index >= indexes) {
+                       seen = realloc(seen, sizeof(*seen)*(index+1));
+                       lastcount = realloc(lastcount,
+                           sizeof(*lastcount)*(index+1));
+
+                       /* Initalize the new slots */
+                       for (i = indexes; i <= index; i++) {
+                               seen[i] = 0;
+                       }
+                       indexes = index+1;
+               }
+
+               /*
+                * If this is the first time we've seen this interface,
+                * set the last values to the current ones.  That causes
+                * us to see no bandwidth on the interface the first
+                * time, but that's OK.
+                */
+               if (!seen[index]) {
+                       seen[index] = 1;
+                       lastcount[index].in_bytes = ifm->ifm_data.ifi_ibytes;
+                       lastcount[index].out_bytes = ifm->ifm_data.ifi_obytes;
+                       lastcount[index].in_pkts = ifm->ifm_data.ifi_ipackets;
+                       lastcount[index].out_pkts = ifm->ifm_data.ifi_opackets;
+               }
+
+               traffic.in_bytes = counterdiff(lastcount[index].in_bytes,
+                   ifm->ifm_data.ifi_ibytes, ULONG_MAX, 0);
+               traffic.out_bytes = counterdiff(lastcount[index].out_bytes,
+                   ifm->ifm_data.ifi_obytes, ULONG_MAX, 0);
+               traffic.in_pkts = counterdiff(lastcount[index].in_pkts,
+                   ifm->ifm_data.ifi_ipackets, ULONG_MAX, 0);
+               traffic.out_pkts = counterdiff(lastcount[index].out_pkts,
+                   ifm->ifm_data.ifi_opackets, ULONG_MAX, 0);
+
+               lastcount[index].in_bytes = ifm->ifm_data.ifi_ibytes;
+               lastcount[index].out_bytes = ifm->ifm_data.ifi_obytes;
+               lastcount[index].in_pkts = ifm->ifm_data.ifi_ipackets;
+               lastcount[index].out_pkts = ifm->ifm_data.ifi_opackets;
+
+#ifdef NETBW_DEBUG
+               if_indextoname(index, name);
+               printf("%s: \n", name);
+               printf("\topackets=%llu ipackets=%llu\n",
+                   traffic.out_pkts, traffic.in_pkts);
+               printf("\tobytes=%llu ibytes=%llu\n",
+                   traffic.out_bytes, traffic.in_bytes);
+#endif
+
+               if (timerisset(&last_time)) {
+                       ibytes += (double)traffic.in_bytes / 
timertod(&time_diff);
+                       obytes += (double)traffic.out_bytes / 
timertod(&time_diff);
+                       ipkts += (double)traffic.in_pkts / timertod(&time_diff);
+                       opkts += (double)traffic.out_pkts / 
timertod(&time_diff);
+               }
+       }
+       free(buf);
+
+       /* Save the values from this time */
+       last_time = this_time;
+       o_ibytes = ibytes;
+       o_obytes = obytes;
+       o_ipkts = ipkts;
+       o_opkts = opkts;
+
+output:
+       if (in_bytes != NULL)
+               *in_bytes = o_ibytes;
+       if (out_bytes != NULL)
+               *out_bytes = o_obytes;
+       if (in_pkts != NULL)
+               *in_pkts = o_ipkts;
+       if (out_pkts != NULL)
+               *out_pkts = o_opkts;
+}
+
+static uint64_t
+counterdiff(uint64_t oldval, uint64_t newval, uint64_t maxval, uint64_t 
maxdiff)
+{
+       uint64_t diff;
+
+       if (maxdiff == 0)
+               maxdiff = maxval;
+
+       /* Paranoia */
+       if (oldval > maxval || newval > maxval)
+               return 0;
+
+       /*
+        * Tackle the easy case.  Don't worry about maxdiff here because
+        * we're SOL if it happens (i.e. assuming a reset just makes
+        * matters worse).
+        */
+       if (oldval <= newval)
+               return (newval - oldval);
+
+       /*
+         * Now the tricky part.  If we assume counters never get reset,
+         * this is easy.  Unfortunaly, they do get reset on some
+         * systems, so we need to try and deal with that.  Our huristic
+         * is that if out difference is greater then maxdiff and newval
+         * is less or equal to maxdiff, then we've probably been reset
+         * rather then actually wrapping.  Obviously, you need to be
+         * careful to poll often enough that you won't exceed maxdiff or
+         * you will get undersized numbers when you do wrap.
+        */
+       diff = maxval - oldval + newval;
+       if (diff > maxdiff && newval <= maxdiff)
+               return newval;
+
+       return diff;
+}
Index: lib/ganglia/net.h
===================================================================
RCS file: /cvsroot/ganglia/monitor-core/lib/ganglia/net.h,v
retrieving revision 1.15
diff -u -p -u -r1.15 net.h
--- lib/ganglia/net.h   7 May 2003 19:32:33 -0000       1.15
+++ lib/ganglia/net.h   6 Oct 2003 23:30:21 -0000
@@ -12,7 +12,7 @@
 #include <netdb.h>
 #include <ganglia/llist.h>
 #include <ganglia/net.h>
-#ifdef BSD
+#ifdef FREEBSD
 #include <sys/types.h>
 #endif
 #include <netinet/in.h>

-- 
Any statement of the form "X is the one, true Y" is FALSE.
PGP fingerprint 655D 519C 26A7 82E7 2529  9BF0 5D8E 8BE9 F238 1AD4

Attachment: pgprIgsp0GX34.pgp
Description: PGP signature

Reply via email to