summaryrefslogtreecommitdiff
path: root/parallel/ganglia-monitor-core/patches/patch-ab
diff options
context:
space:
mode:
Diffstat (limited to 'parallel/ganglia-monitor-core/patches/patch-ab')
-rw-r--r--parallel/ganglia-monitor-core/patches/patch-ab1011
1 files changed, 1011 insertions, 0 deletions
diff --git a/parallel/ganglia-monitor-core/patches/patch-ab b/parallel/ganglia-monitor-core/patches/patch-ab
new file mode 100644
index 00000000000..fd69dddf5f0
--- /dev/null
+++ b/parallel/ganglia-monitor-core/patches/patch-ab
@@ -0,0 +1,1011 @@
+$NetBSD: patch-ab,v 1.1.1.1 2005/02/07 14:33:21 jschauma Exp $
+
+--- /dev/null 2005-02-06 17:33:10.000000000 -0500
++++ gmond/machines/netbsd.c 2005-02-06 17:33:11.000000000 -0500
+@@ -0,0 +1,1006 @@
++/*
++ * First stab at support for metrics in NetBSD
++ * by Jan Schaumann <jschauma@netbsd.org>
++ * Thu Feb 3 22:33:36 EST 2005
++ *
++ */
++
++#include <kvm.h>
++
++#include <sys/param.h>
++#include <sys/mount.h>
++#include <sys/sysctl.h>
++#include <sys/time.h>
++#include <sys/user.h>
++#include <sys/resource.h>
++#include <sys/stat.h>
++#include <sys/swap.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))
++
++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 size_t regetmntinfo(struct statfs **, long);
++static float find_disk_space(double *, double *);
++static int vm_state(int);
++
++static kvm_t *kd = NULL;
++static long pagesize;
++
++/* Function prototypes */
++static long percentages(int cnt, u_int64_t *out, register u_int64_t *new,
++ register u_int64_t *old, u_int64_t *diffs);
++
++/*
++ * This function is called only once by the gmond. Use to
++ * initialize data structures, etc or just return SYNAPSE_SUCCESS;
++ */
++g_val_t
++metric_init(void)
++{
++ g_val_t val;
++ kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "metric_init()");
++ pagesize = sysconf(_SC_PAGESIZE);
++ val.int32 = SYNAPSE_SUCCESS;
++ return val;
++}
++
++g_val_t
++cpu_num_func ( void )
++{
++ g_val_t val;
++ int ncpu;
++ size_t len = sizeof (int);
++ if (sysctlbyname("hw.ncpu", &ncpu, &len, NULL, 0) == -1 || !len)
++ ncpu = 1;
++
++ val.uint16 = ncpu;
++ return val;
++}
++
++g_val_t
++cpu_speed_func ( void )
++{
++ g_val_t val;
++ size_t len;
++ long cpu_speed;
++
++ if (sysctlbyname("machdep.est.frequency.target", &cpu_speed, &len, NULL, 0) == -1)
++ val.uint16 = 0;
++
++ val.uint16 = cpu_speed /= 1000000;
++ return val;
++}
++
++g_val_t
++mem_total_func ( void )
++{
++ g_val_t val;
++ size_t len;
++ int total;
++ int mib[2];
++
++ mib[0] = CTL_HW;
++ mib[1] = HW_PHYSMEM;
++ len = sizeof (total);
++
++ sysctl(mib, 2, &total, &len, NULL, 0);
++ total /= 1024;
++ val.uint32 = total;
++ return val;
++}
++
++g_val_t
++swap_total_func ( void )
++{
++ g_val_t val;
++
++ int mib[2];
++ struct uvmexp_sysctl uvmexp;
++ size_t len;
++ int totswap;
++
++ val.uint32 = 0;
++ totswap = 0;
++
++ mib[0] = CTL_VM;
++ mib[1] = VM_UVMEXP2;
++
++ len = sizeof(uvmexp);
++
++ if((sysctl(mib, 2, &uvmexp, &len, NULL, 0) < 0)
++ || !len)
++ totswap = 0;
++ else
++ totswap = uvmexp.swpages;
++
++ val.uint32 = totswap * (pagesize / 1024);
++
++ return val;
++}
++
++g_val_t
++boottime_func ( void )
++{
++ g_val_t val;
++ struct timeval boottime;
++ int mib[2];
++ size_t size;
++
++ mib[0] = CTL_KERN;
++ mib[1] = KERN_BOOTTIME;
++ size = sizeof(boottime);
++ if (sysctl(mib, 2, &boottime, &size, NULL, 0) == -1)
++ val.uint32 = 0;
++
++ val.uint32 = boottime.tv_sec;
++
++ return val;
++}
++
++g_val_t
++sys_clock_func ( void )
++{
++ g_val_t val;
++
++ val.uint32 = time(NULL);
++ return val;
++}
++
++g_val_t
++machine_type_func ( void )
++{
++ g_val_t val;
++ char machine_type[MAX_G_STRING_SIZE];
++ size_t len = MAX_G_STRING_SIZE;
++ if (sysctlbyname("hw.machine", &machine_type, &len, NULL, 0) == -1 || !len)
++ strncpy( val.str, "x86", MAX_G_STRING_SIZE );
++
++ strncpy( val.str, machine_type, MAX_G_STRING_SIZE );
++ return val;
++}
++
++g_val_t
++os_name_func ( void )
++{
++ g_val_t val;
++ char osname[MAX_G_STRING_SIZE];
++ size_t len = MAX_G_STRING_SIZE;
++ if (sysctlbyname("kern.ostype", &osname, &len, NULL, 0) == -1 || !len)
++ strncpy( val.str, "NetBSD", MAX_G_STRING_SIZE );
++
++ strncpy( val.str, osname, MAX_G_STRING_SIZE );
++
++ return val;
++}
++
++g_val_t
++os_release_func ( void )
++{
++ g_val_t val;
++ int mib[2];
++ size_t len;
++ char *prefix, buf[1024];
++
++ prefix = "";
++
++ mib[0] = CTL_KERN;
++ mib[1] = KERN_OSRELEASE;
++ len = sizeof(buf);
++ if (sysctl(mib, 2, &buf, &len, NULL, 0) == -1)
++ strncpy( val.str, "Unknown", MAX_G_STRING_SIZE );
++
++ strncpy( val.str, buf, MAX_G_STRING_SIZE );
++
++ return val;
++}
++
++/* Get the CPU state given by index, from kern.cp_time
++ * Use the constants in <sys/dkstat.h>
++ * CP_USER=0, CP_NICE=1, CP_SYS=2, CP_INTR=3, CP_IDLE=4
++ */
++int cpu_state(int which) {
++
++ static u_int64_t cp_time[CPUSTATES];
++ static u_int64_t cp_old[CPUSTATES];
++ static u_int64_t cp_diff[CPUSTATES];
++ static u_int64_t cpu_states[CPUSTATES];
++ static long tot;
++ size_t len = sizeof(cp_time);
++ int mib[2];
++
++ mib[0] = CTL_KERN;
++ mib[1] = KERN_CP_TIME;
++
++ /* Copy the last cp_time into cp_old */
++ memcpy(&cp_old, &cp_time, CPUSTATES*sizeof(long));
++ /* puts kern.cp_time array into cp_time */
++ if (sysctl(mib, 2, &cp_time, &len, NULL, 0) == -1 || !len)
++ return 0.0;
++ /* Use percentages function lifted from top(1) to figure percentages */
++ tot = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
++
++ return cpu_states[which];
++}
++
++g_val_t
++cpu_user_func ( void )
++{
++ g_val_t val;
++ int res;
++
++ res = cpu_state(CP_USER);
++ val.f = (float)res/10;
++ return val;
++}
++
++g_val_t
++cpu_nice_func ( void )
++{
++ g_val_t val;
++ int res;
++
++ res = cpu_state(CP_NICE);
++ val.f = (float)res/10;
++
++ return val;
++}
++
++g_val_t
++cpu_system_func ( void )
++{
++ g_val_t val;
++ int res;
++
++ res = cpu_state(CP_SYS);
++ val.f = (float)res/10;
++
++ return val;
++}
++
++g_val_t
++cpu_idle_func ( void )
++{
++ g_val_t val;
++ int res;
++
++ res = cpu_state(CP_IDLE);
++ val.f = (float)res/10;
++
++ return val;
++}
++
++g_val_t
++cpu_aidle_func ( void )
++{
++ g_val_t val;
++
++ val.f = 0.0;
++ return val;
++}
++
++g_val_t
++load_one_func ( void )
++{
++ g_val_t val;
++ double load[3];
++
++ getloadavg(load, 3);
++ val.f = load[0];
++ return val;
++}
++
++g_val_t
++load_five_func ( void )
++{
++ g_val_t val;
++ double load[3];
++
++ getloadavg(load, 3);
++
++ val.f = load[1];
++ return val;
++}
++
++g_val_t
++load_fifteen_func ( void )
++{
++ g_val_t val;
++ double load[3];
++
++ getloadavg(load, 3);
++ val.f = load[2];
++ return val;
++}
++
++g_val_t
++proc_total_func ( void )
++{
++ g_val_t val;
++ int mib[3];
++ size_t len;
++
++ mib[0] = CTL_KERN;
++ mib[1] = KERN_PROC;
++ mib[2] = KERN_PROC_ALL;
++
++ sysctl(mib, 3, NULL, &len, NULL, 0);
++
++ val.uint32 = (len / sizeof (struct kinfo_proc));
++
++ return val;
++}
++
++
++/*
++ * Don't know how to do this yet..
++ */
++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 SACTIVE:
++ case SIDL:
++ val.uint32++;
++ break;
++ }
++ }
++
++ if (val.uint32 > 0)
++ val.uint32--;
++
++output:
++ return val;
++}
++
++g_val_t
++mem_free_func ( void )
++{
++ g_val_t val;
++ size_t len;
++ struct vmtotal vminfo;
++ int mib[2];
++
++ len = sizeof(vminfo);
++ mib[0] = CTL_VM;
++ mib[1] = VM_METER;
++ if (sysctl(mib, 2, &vminfo, &len, NULL, 0) < 0)
++ val.uint32 = 0;
++ else
++ val.uint32 = vminfo.t_free * (pagesize / 1024);
++ return val;
++}
++
++g_val_t
++mem_shared_func ( void )
++{
++ g_val_t val;
++ size_t len;
++ struct vmtotal vminfo;
++ int mib[2];
++
++ len = sizeof(vminfo);
++ mib[0] = CTL_VM;
++ mib[1] = VM_METER;
++ if (sysctl(mib, 2, &vminfo, &len, NULL, 0) < 0)
++ val.uint32 = 0;
++ else
++ val.uint32 = (vminfo.t_vmshr + vminfo.t_rmshr) * (pagesize / 1024);
++ return val;
++}
++
++g_val_t
++mem_buffers_func ( void )
++{
++ g_val_t val;
++ size_t len;
++ int buffers;
++
++ len = sizeof (buffers);
++ if((sysctlbyname("vfs.nkmempages", &buffers, &len, NULL, 0) == -1) || !len)
++ buffers = 0;
++ buffers /= 1024;
++
++ val.uint32 = buffers;
++ return val;
++}
++
++g_val_t
++mem_cached_func ( void )
++{
++ g_val_t val;
++ size_t len;
++ int cache;
++ struct uvmexp_sysctl uvmexp;
++ int mib[2];
++
++ mib[0] = CTL_VM;
++ mib[1] = VM_UVMEXP2;
++
++ len = sizeof(uvmexp);
++
++ if((sysctl(mib, 2, &uvmexp, &len, NULL, 0) < 0)
++ || !len)
++ cache = 0;
++ else
++ cache = uvmexp.execpages + uvmexp.filepages;
++
++ val.uint32 = cache * (pagesize / 1024);
++ return val;
++}
++
++g_val_t
++swap_free_func ( void )
++{
++ g_val_t val;
++
++ int mib[2];
++ struct uvmexp_sysctl uvmexp;
++ size_t len;
++ int totswapf;
++
++ val.uint32 = 0;
++ totswapf = 0;
++
++ mib[0] = CTL_VM;
++ mib[1] = VM_UVMEXP2;
++
++ len = sizeof(uvmexp);
++
++ if((sysctl(mib, 2, &uvmexp, &len, NULL, 0) < 0)
++ || !len)
++ totswapf = 0;
++ else
++ totswapf = uvmexp.swpages - uvmexp.swpginuse;
++
++ val.uint32 = totswapf * (pagesize / 1024);
++
++ return val;
++}
++
++
++static int
++find_mtu(const struct intf_entry *entry, void *arg)
++{
++ unsigned int mtu;
++ unsigned int *min = (unsigned int *) arg;
++
++ /* Only consider interfaces that are up. */
++ if (! entry->intf_flags & INTF_FLAG_UP)
++ return 0;
++
++ mtu=entry->intf_mtu;
++ if ( !*min || *min>mtu)
++ *min=mtu;
++
++ return 0;
++}
++
++g_val_t
++mtu_func ( void )
++{
++ /* We want to find the minimum MTU (Max packet size) over all UP interfaces.
++*/
++ unsigned int min=0;
++ g_val_t val;
++
++ intf_t *intf;
++ intf = intf_open();
++ intf_loop(intf, find_mtu, &min);
++ intf_close(intf);
++ val.uint32 = min;
++
++ /* A val of 0 means there are no UP interfaces. Shouldn't happen. */
++ return val;
++}
++
++
++/*
++ * Function to get cpu percentages.
++ * Might be changed ever so slightly, but is still mostly:
++ * AUTHOR: Christos Zoulas <christos@ee.cornell.edu>
++ * Steven Wallace <swallace@freebsd.org>
++ * Wolfram Schneider <wosch@FreeBSD.org>
++ *
++ * $FreeBSD: src/usr.bin/top/machine.c,v 1.29.2.2 2001/07/31 20:27:05 tmm Exp $
++ */
++
++static long percentages(int cnt, u_int64_t *out, register u_int64_t *new,
++ register u_int64_t *old, u_int64_t *diffs) {
++
++ register int i;
++ register u_int64_t change;
++ register u_int64_t total_change;
++ register u_int64_t *dp;
++ long half_total;
++
++ /* initialization */
++ total_change = 0;
++ dp = diffs;
++
++ /* calculate changes for each state and the overall change */
++ for (i = 0; i < cnt; i++) {
++ if ((change = *new - *old) < 0) {
++ /* this only happens when the counter wraps */
++ change = (int)
++ ((unsigned long)*new-(unsigned long)*old);
++ }
++ total_change += (*dp++ = change);
++ *old++ = *new++;
++ }
++ /* avoid divide by zero potential */
++ if (total_change == 0) { total_change = 1; }
++
++ /* calculate percentages based on overall change, rounding up */
++ half_total = total_change / 2l;
++
++ /* Do not divide by 0. Causes Floating point exception */
++ if(total_change) {
++ for (i = 0; i < cnt; i++) {
++ *out++ = (int)((*diffs++ * 1000 + half_total) / total_change);
++ }
++ }
++
++ /* return the total in case the caller wants to use it */
++ 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 NetBSD 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;
++ 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";
++
++ mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
++ mntsize = regetmntinfo(&mntbuf, mntsize);
++ 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)
++{
++ int i, j;
++ struct statfs *mntbuf;
++
++ mntbuf = *mntbufp;
++ j = 0;
++ for (i = 0; i < mntsize; i++) {
++ struct statfs layerbuf = mntbuf[i];
++ (void)statfs(mntbuf[i].f_mntonname, &mntbuf[j]);
++ /*
++ * If the FS name changed, then new data is for
++ * a different layer and we don't want it.
++ */
++ if (memcmp(layerbuf.f_mntfromname,
++ mntbuf[j].f_mntfromname, MNAMELEN))
++ mntbuf[j] = layerbuf;
++ j++;
++ }
++ return (j);
++}
++
++
++
++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;
++}