/* * sysctl() interface * e.g. BSD/OS, NetBSD, OpenBSD, later Darwin releases */ #include #include #include #include #include #include #include #include #if defined(freebsd3) #include #if !defined(CPUSTATES) #include #endif #else #include #endif #include #include #include #ifdef HAVE_VM_VM_PARAM_H #include #endif #ifdef HAVE_VM_VM_EXTERN_H #include #endif #ifdef HAVE_UVM_UVM_EXTERN_H #include #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 NETSNMP_CPU_STATS #elif defined(KERN_CPTIME) /* OpenBSD */ #define NETSNMP_KERN_CPU KERN_CPTIME #elif defined(freebsd3) #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(freebsd3) /* FreeBSD */ #if __FreeBSD_version >= 1200028 #define VMMETER_TYPE uint64_t #else #define VMMETER_TYPE u_int #endif struct __vmmeter { VMMETER_TYPE v_intr; VMMETER_TYPE v_swtch; VMMETER_TYPE v_swappgsin; VMMETER_TYPE v_swappgsout; VMMETER_TYPE v_swapin; VMMETER_TYPE v_swapout; }; #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(freebsd3) && !defined(__NetBSD__) int cpu_mib[] = { CTL_KERN, NETSNMP_KERN_CPU }; #endif #ifdef freebsd3 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; netsnmp_cpu_info *cpu = netsnmp_cpu_get_byIdx( -1, 0 ); #if defined(freebsd3) || 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 */ #ifdef freebsd3 #define GET_VM_STATS(space, name) sysctlbyname("vm.stats." #space "." #name, &mem_stats.name, &len, NULL, 0) { size_t len; len = sizeof(VMMETER_TYPE); GET_VM_STATS(sys, v_intr); GET_VM_STATS(sys, v_swtch); GET_VM_STATS(vm, v_swappgsin); GET_VM_STATS(vm, v_swappgsout); GET_VM_STATS(vm, v_swapin); GET_VM_STATS(vm, v_swapout); } #undef GET_VM_STATS #else { static const int mem_mib[] = { CTL_VM, NETSNMP_VM_STATS }; size_t mem_size = sizeof(mem_stats); sysctl(mem_mib, sizeof(mem_mib) / sizeof(mem_mib[0]), &mem_stats, &mem_size, NULL, 0); netsnmp_assert(mem_size == sizeof(mem_stats)); } #endif /* * Interrupt/Context Switch statistics * XXX - Do these really belong here ? */ 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(freebsd3) 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; }