blob: 5ecb68eff17c0f8359604657d986cb3f8c75e81c [file] [log] [blame]
/*
* sysctl() interface
* e.g. BSD/OS, NetBSD, OpenBSD, later Darwin releases
*/
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-features.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include <net-snmp/agent/hardware/cpu.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#if defined(__FreeBSD__)
#include <sys/resource.h>
#if !defined(CPUSTATES)
#include <sys/dkstat.h>
#endif
#else
#include <sys/sched.h>
#endif
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/vmmeter.h>
#ifdef HAVE_VM_VM_PARAM_H
#include <vm/vm_param.h>
#endif
#ifdef HAVE_VM_VM_EXTERN_H
#include <vm/vm_extern.h>
#endif
netsnmp_feature_require(hardware_cpu_copy_stats)
void _cpu_copy_stats( netsnmp_cpu_info *cpu );
/*
* Initialise the list of CPUs on the system
* (including descriptions)
*/
void init_cpu_sysctl( void ) {
int i, n;
size_t siz;
int ncpu_mib[] = { CTL_HW, HW_NCPU };
#if !(defined(__NetBSD__) && ( defined(__i386__) || defined(__x86_64__) ) )
int model_mib[] = { CTL_HW, HW_MODEL };
#endif
char descr[ SNMP_MAXBUF ];
netsnmp_cpu_info *cpu = netsnmp_cpu_get_byIdx( -1, 1 );
strcpy(cpu->name, "Overall CPU statistics");
siz = sizeof(n);
sysctl(ncpu_mib, 2, &n, &siz, NULL, 0);
if ( n <= 0 )
n = 1; /* Single CPU system */
siz = sizeof(descr);
#if defined(__NetBSD__) && ( defined(__i386__) || defined(__x86_64__) )
sysctlbyname("machdep.cpu_brand", descr, &siz, NULL, 0);
#else
sysctl(model_mib, 2, descr, &siz, NULL, 0);
#endif
for ( i = 0; i < n; i++ ) {
cpu = netsnmp_cpu_get_byIdx( i, 1 );
cpu->status = 2; /* running */
sprintf( cpu->name, "cpu%d", i );
sprintf( cpu->descr, "%s", descr );
}
cpu_num = n;
}
#if defined(__NetBSD__)
#define NETSNMP_CPU_STATS uint64_t
#else
#define NETSNMP_CPU_STATS long
#endif
#if defined(__NetBSD__)
#define NETSNMP_KERN_CPU KERN_CP_TIME
#define NETSNMP_KERN_MCPU
#define NETSNMP_KERN_MCPU_TYPE NETSNMP_CPU_STATS
#elif defined(KERN_CPUSTATS) /* BSDi */
#define NETSNMP_KERN_CPU KERN_CPUSTATS
#elif defined(KERN_CPTIME2) /* OpenBSD */
#define NETSNMP_KERN_CPU KERN_CPTIME
#define NETSNMP_KERN_MCPU
#define NETSNMP_KERN_MCPU_TYPE u_int64_t
#elif defined(KERN_CPTIME) /* OpenBSD */
#define NETSNMP_KERN_CPU KERN_CPTIME
#elif defined(__FreeBSD__)
#define NETSNMP_KERN_MCPU 1 /* Enable support for multi-cpu stats. Valid for FreeBSD >=6.4, >=7.1, >=8.0 and beyond */
#define NETSNMP_KERN_MCPU_TYPE NETSNMP_CPU_STATS
#else
#error "No CPU statistics sysctl token"
#endif
/*
Need to check details before enabling this!
#if defined(KERN_MPCPUSTATS)
#define NETSNMP_KERN_MCPU KERN_MPCPUSTATS
#define NETSNMP_KERN_MCPU_TYPE struct mpcpustats
#elif defined(KERN_MP_CPUSTATS)
#define NETSNMP_KERN_MCPU KERN_MP_CPUSTATS
#define NETSNMP_KERN_MCPU_TYPE struct cpustats
#endif
*/
#if defined(VM_UVMEXP2) || defined(VM_UVMEXP)
#define NS_VM_INTR intrs
#define NS_VM_SWTCH swtch
#define NS_VM_PAGEIN pageins
#define NS_VM_PAGEOUT pdpageouts
#ifdef HAVE_STRUCT_UVMEXP_PGSWAPIN
#define NS_VM_SWAPIN pgswapin
#define NS_VM_SWAPOUT pgswapout
#else
#define NS_VM_SWAPIN swapins
#define NS_VM_SWAPOUT swapouts
#endif
#if defined(VM_UVMEXP2) /* NetBSD 1.6+ */
#define NETSNMP_VM_STATS VM_UVMEXP2
#define NETSNMP_VM_STATS_TYPE struct uvmexp_sysctl
#else /* VM_UVMEXP */ /* OpenBSD 3+, NetBSD 1.6+ */
#define NETSNMP_VM_STATS VM_UVMEXP
#define NETSNMP_VM_STATS_TYPE struct uvmexp
#endif /* VM_UVMEXP2 || VM_UVMEXP */
#elif defined(__FreeBSD__) /* FreeBSD */
#define NETSNMP_VM_STATS VM_METER
#define NETSNMP_VM_STATS_TYPE struct vmmeter
#define NS_VM_INTR v_intr
#define NS_VM_SWTCH v_swtch
#define NS_VM_PAGEIN v_swappgsin
#define NS_VM_PAGEOUT v_swappgsout
#define NS_VM_SWAPIN v_swapin
#define NS_VM_SWAPOUT v_swapout
#elif defined(VM_METER) /* OpenBSD, NetBSD */
#define NETSNMP_VM_STATS VM_METER
#define NETSNMP_VM_STATS_TYPE struct vmtotal
#elif defined(VM_CNT) /* BSDi */
#define NETSNMP_VM_STATS VM_CNT
#define NETSNMP_VM_STATS_TYPE struct vmmeter
#define NS_VM_INTR v_intr
#define NS_VM_SWTCH v_swtch
#undef NS_VM_PAGEIN
#undef NS_VM_PAGEOUT
#define NS_VM_SWAPIN v_swpin
#define NS_VM_SWAPOUT v_swpout
#endif
/*
* Load the latest CPU usage statistics
*/
int netsnmp_cpu_arch_load( netsnmp_cache *cache, void *magic ) {
/*
* Strictly speaking, BSDi ought to use
* "struct cpustats cpu_stats"
* but this array was used in the previous code, and
* is correct for the {Open,Net}BSD versions too.
* Don't fight it, Dave - go with the flow....
*/
NETSNMP_CPU_STATS cpu_stats[CPUSTATES];
size_t cpu_size = sizeof(cpu_stats);
#if !defined(__FreeBSD__) && !defined(__NetBSD__)
int cpu_mib[] = { CTL_KERN, NETSNMP_KERN_CPU };
#endif
#ifdef __FreeBSD__
static int cp_times = -1;
#endif
#ifdef KERN_CPTIME2
int mcpu_mib[] = { CTL_KERN, KERN_CPTIME2, 0 };
#endif
#ifdef NETSNMP_KERN_MCPU
int i;
int act_cpu = cpu_num;
NETSNMP_KERN_MCPU_TYPE *mcpu_stats;
size_t mcpu_size;
#endif
NETSNMP_VM_STATS_TYPE mem_stats;
int mem_mib[] = { CTL_VM, NETSNMP_VM_STATS };
size_t mem_size = sizeof(NETSNMP_VM_STATS_TYPE);
netsnmp_cpu_info *cpu = netsnmp_cpu_get_byIdx( -1, 0 );
#if defined(__FreeBSD__) || defined(__NetBSD__)
sysctlbyname("kern.cp_time", cpu_stats, &cpu_size, NULL, 0);
#else
sysctl(cpu_mib, 2, cpu_stats, &cpu_size, NULL, 0);
#endif
cpu->user_ticks = cpu_stats[CP_USER];
cpu->nice_ticks = cpu_stats[CP_NICE];
cpu->sys2_ticks = cpu_stats[CP_SYS]+cpu_stats[CP_INTR];
cpu->kern_ticks = cpu_stats[CP_SYS];
cpu->idle_ticks = cpu_stats[CP_IDLE];
cpu->intrpt_ticks = cpu_stats[CP_INTR];
/* wait_ticks, sirq_ticks unused */
/*
* Interrupt/Context Switch statistics
* XXX - Do these really belong here ?
*/
sysctl(mem_mib, 2, &mem_stats, &mem_size, NULL, 0);
cpu->nInterrupts = mem_stats.NS_VM_INTR;
cpu->nCtxSwitches = mem_stats.NS_VM_SWTCH;
cpu->swapIn = mem_stats.NS_VM_SWAPIN;
cpu->swapOut = mem_stats.NS_VM_SWAPOUT;
#ifdef NS_VM_PAGEIN
cpu->pageIn = mem_stats.NS_VM_PAGEIN;
#endif
#ifdef NS_VM_PAGEOUT
cpu->pageOut = mem_stats.NS_VM_PAGEOUT;
#endif
#ifdef NETSNMP_KERN_MCPU
#if defined(KERN_CPTIME2)
mcpu_size = cpu_num*sizeof(cpu_stats);
mcpu_stats = malloc(mcpu_size);
#elif defined(__NetBSD__)
mcpu_size = cpu_num*sizeof(cpu_stats);
mcpu_stats = malloc(mcpu_size);
sysctlbyname("kern.cp_time", mcpu_stats, &mcpu_size, NULL, 0);
#elif defined(__FreeBSD__)
if (cp_times == -1) {
int ret = sysctlbyname("kern.cp_times", NULL, &mcpu_size, NULL, 0);
cp_times = ret == -1 ? 0 : 1;
}
if (cp_times) {
sysctlbyname("kern.cp_times", NULL, &mcpu_size, NULL, 0);
mcpu_stats = malloc(mcpu_size);
sysctlbyname("kern.cp_times", mcpu_stats, &mcpu_size, NULL, 0);
}
else {
mcpu_size = sizeof(cpu_stats);
mcpu_stats = malloc(mcpu_size);
sysctlbyname("kern.cp_time", mcpu_stats, &mcpu_size, NULL, 0);
act_cpu = 1;
}
#endif
for ( i = 0; i < act_cpu; i++ ) {
cpu = netsnmp_cpu_get_byIdx( i, 0 );
/* XXX - per-CPU statistics - mcpu_mib[i].??? */
#ifdef KERN_CPTIME2
mcpu_mib[2] = i;
sysctl(mcpu_mib, 3, mcpu_stats+i*CPUSTATES, &mcpu_size, NULL, 0);
#endif
/* Almost copy & paste of previous cpu stats stuff :) */
cpu->user_ticks = mcpu_stats[(i*CPUSTATES)+CP_USER];
cpu->nice_ticks = mcpu_stats[(i*CPUSTATES)+CP_NICE];
cpu->sys2_ticks = mcpu_stats[(i*CPUSTATES)+CP_SYS]+mcpu_stats[(i*CPUSTATES)+CP_INTR];
cpu->kern_ticks = mcpu_stats[(i*CPUSTATES)+CP_SYS];
cpu->idle_ticks = mcpu_stats[(i*CPUSTATES)+CP_IDLE];
cpu->intrpt_ticks = mcpu_stats[(i*CPUSTATES)+CP_INTR];
/* wait_ticks, sirq_ticks unused */
/*
* Interrupt/Context Switch statistics
* XXX - Do these really belong here ?
*/
/* There's no real need to execute another sysctl()
*
* sysctl(mem_mib, 2, &mem_stats, &mem_size, NULL, 0);
*/
cpu->nInterrupts = mem_stats.NS_VM_INTR;
cpu->nCtxSwitches = mem_stats.NS_VM_SWTCH;
cpu->swapIn = mem_stats.NS_VM_SWAPIN;
cpu->swapOut = mem_stats.NS_VM_SWAPOUT;
#ifdef NS_VM_PAGEIN
cpu->pageIn = mem_stats.NS_VM_PAGEIN;
#endif
#ifdef NS_VM_PAGEOUT
cpu->pageOut = mem_stats.NS_VM_PAGEOUT;
#endif
}
free(mcpu_stats);
#else /* NETSNMP_KERN_MCPU */
/* Copy "overall" figures to cpu0 entry */
_cpu_copy_stats( cpu );
#endif /* NETSNMP_KERN_MCPU */
return 0;
}