[collectd] interface plugin on macosx

Robert Viduya robert at oit.gatech.edu
Thu Jun 11 14:02:22 CEST 2015


The interface plugin on macosx uses getifaddrs to retrieve the network interface statistics from the kernel.  This call returns 32-bit values and, with gigabit network interfaces, they can wrap in less than a minute.  The following patch uses sysctl instead if it’s available which returns 64-bit counters.

Tested to work under MacOSX 10.10.
 
*** collectd-master.orig/src/interface.c	Thu Jun 11 05:36:12 2015
--- collectd-master/src/interface.c	Thu Jun 11 07:55:54 2015
***************
*** 58,63 ****
--- 58,70 ----
  # include <libperfstat.h>
  #endif
  
+ #if HAVE_SYSCTL
+ #include <sys/sysctl.h>
+ #include <net/if_dl.h>
+ #include <net/route.h>
+ #undef HAVE_GETIFADDRS	/* prefer sysctl over getifaddrs */
+ #endif
+ 
  /*
   * Various people have reported problems with `getifaddrs' and varying versions
   * of `glibc'. That's why it's disabled by default. Since more statistics are
***************
*** 76,82 ****
  static int pnif;
  #endif /* HAVE_PERFSTAT */
  
! #if !HAVE_GETIFADDRS && !KERNEL_LINUX && !HAVE_LIBKSTAT && !HAVE_LIBSTATGRAB && !HAVE_PERFSTAT
  # error "No applicable input method."
  #endif
  
--- 83,89 ----
  static int pnif;
  #endif /* HAVE_PERFSTAT */
  
! #if !HAVE_GETIFADDRS && !KERNEL_LINUX && !HAVE_LIBKSTAT && !HAVE_LIBSTATGRAB && !HAVE_PERFSTAT && !HAVE_SYSCTL
  # error "No applicable input method."
  #endif
  
***************
*** 372,378 ****
  		if_submit (ifstat[i].name, "if_packets", ifstat[i].ipackets ,ifstat[i].opackets);
  		if_submit (ifstat[i].name, "if_errors", ifstat[i].ierrors, ifstat[i].oerrors );
  	}
! #endif /* HAVE_PERFSTAT */
  
  	return (0);
  } /* int interface_read */
--- 379,437 ----
  		if_submit (ifstat[i].name, "if_packets", ifstat[i].ipackets ,ifstat[i].opackets);
  		if_submit (ifstat[i].name, "if_errors", ifstat[i].ierrors, ifstat[i].oerrors );
  	}
! 
! #elif defined(HAVE_SYSCTL)
! 
! 	int			mib[6], i;
! 	size_t			len, nlen;
! 	char			*buf, *cur, errbuf[1024], interface_name[64];
! 	struct if_msghdr	*ifm;
! 
! 	mib[0] = CTL_NET;
! 	mib[1] = PF_ROUTE;
! 	mib[2] = 0;
! 	mib[3] = 0;
! 	mib[4] = NET_RT_IFLIST2;
! 	mib[5] = 0;
! 
! 	if (sysctl (mib, 6, NULL, &len, NULL, 0) == -1) {
! 	    WARNING ("interface plugin: sysctl (get-len): %s", sstrerror (errno, errbuf, sizeof (errbuf)));
! 	    return (-1);
! 	}
! 	if ((buf = malloc (len)) == NULL) {
! 	    WARNING ("interface plugin: malloc: %s", sstrerror (errno, errbuf, sizeof (errbuf)));
! 	    return (-1);
! 	}
! 	if (sysctl (mib, 6, buf, &len, NULL, 0) == -1) {
! 	    WARNING ("interface plugin: sysctl (fill-buf): %s", sstrerror (errno, errbuf, sizeof (errbuf)));
! 	    return (-1);
! 	}
! 	cur = buf;
! 	while (cur < (buf + len)) {
! 	    ifm = (struct if_msghdr *) cur;
! 	    cur += ifm->ifm_msglen;
! 	    if (ifm->ifm_type == RTM_IFINFO2) {
! 		struct if_msghdr2 *if2m = (struct if_msghdr2 *) ifm;
! 		struct sockaddr *s = (struct sockaddr *) (if2m + 1);
! 		if (s->sa_family == AF_LINK) {
! 		    struct sockaddr_dl *sdl = (struct sockaddr_dl *) s;
! 		    if (sdl->sdl_nlen > sizeof (interface_name) - 1)
! 			WARNING ("interface plugin: interface name too long, truncating");
! 		    nlen = sdl->sdl_nlen;
! 		    if (nlen > sizeof (interface_name) - 1)
! 			nlen = sizeof (interface_name) - 1;
! 		    for (i = 0; i < nlen; i++)
! 			    interface_name[i] = sdl->sdl_data[i];
! 		    interface_name[i] = '\0';
! 		    if_submit (interface_name, "if_octets", if2m->ifm_data.ifi_ibytes, if2m->ifm_data.ifi_obytes);
! 		    if_submit (interface_name, "if_packets", if2m->ifm_data.ifi_ipackets, if2m->ifm_data.ifi_opackets);
! 		    if_submit (interface_name, "if_errors", if2m->ifm_data.ifi_ierrors, if2m->ifm_data.ifi_oerrors);
! 		}
! 	    }
! 	}
! 	free (buf);
! 
! #endif /* HAVE_SYSCTL */
  
  	return (0);
  } /* int interface_read */




More information about the collectd mailing list