| #include <net-snmp/net-snmp-config.h> |
| #include <net-snmp/net-snmp-includes.h> |
| #include <net-snmp/agent/net-snmp-agent-includes.h> |
| #include <net-snmp/agent/auto_nlist.h> |
| #include <net-snmp/agent/hardware/memory.h> |
| |
| #include <unistd.h> |
| #include <sys/param.h> |
| #include <sys/fcntl.h> |
| #include <sys/sysctl.h> |
| #include <sys/vmmeter.h> |
| #include <kvm.h> |
| |
| #if HAVE_SYS_VMPARAM_H |
| #include <sys/vmparam.h> |
| #else |
| #include <vm/vm_param.h> |
| #endif |
| |
| #define SUM_SYMBOL "cnt" |
| #define BUFSPACE_SYMBOL "bufspace" |
| |
| quad_t swapTotal; |
| quad_t swapUsed; |
| quad_t swapFree; |
| |
| static int swapmode(long); |
| |
| |
| /* |
| * Load the latest memory usage statistics |
| */ |
| int netsnmp_mem_arch_load( netsnmp_cache *cache, void *magic ) { |
| |
| netsnmp_memory_info *mem; |
| long pagesize; |
| int nswap; |
| |
| #if !defined(VM_TOTAL) |
| unsigned int free_mem; |
| size_t free_size = sizeof(free_mem); |
| unsigned int mem_pages; |
| #else |
| struct vmtotal total; |
| size_t total_size = sizeof(total); |
| int total_mib[] = { CTL_VM, VM_TOTAL }; |
| #endif |
| |
| u_long phys_mem; |
| u_long user_mem; |
| unsigned int cache_count; |
| unsigned int cache_max; |
| unsigned int bufspace; |
| unsigned int maxbufspace; |
| unsigned int inact_count; |
| size_t mem_size = sizeof(phys_mem); |
| size_t cache_size = sizeof(cache_count); |
| size_t buf_size = sizeof(bufspace); |
| size_t inact_size = sizeof(inact_count); |
| int phys_mem_mib[] = { CTL_HW, HW_PHYSMEM }; |
| int user_mem_mib[] = { CTL_HW, HW_USERMEM }; |
| |
| /* |
| * Retrieve the memory information from the underlying O/S... |
| */ |
| #if !defined(VM_TOTAL) |
| sysctlbyname("vm.stats.vm.v_free_count", &free_mem, &free_size, NULL, 0); |
| sysctlbyname("vm.stats.vm.v_page_count", &mem_pages, &free_size, NULL, 0); |
| #else |
| sysctl(total_mib, 2, &total, &total_size, NULL, 0); |
| #endif |
| sysctl(phys_mem_mib, 2, &phys_mem, &mem_size, NULL, 0); |
| sysctl(user_mem_mib, 2, &user_mem, &mem_size, NULL, 0); |
| sysctlbyname("vm.stats.vm.v_cache_count", &cache_count, &cache_size, NULL, 0); |
| sysctlbyname("vm.stats.vm.v_cache_max", &cache_max, &cache_size, NULL, 0); |
| sysctlbyname("vm.stats.vm.v_inactive_count", &inact_count, &inact_size, NULL, 0); |
| sysctlbyname("vfs.bufspace", &bufspace, &buf_size, NULL, 0); |
| sysctlbyname("vfs.maxbufspace", &maxbufspace, &buf_size, NULL, 0); |
| #ifndef freebsd4 |
| pagesize = 1024; |
| #else |
| pagesize = getpagesize(); |
| #endif |
| |
| /* |
| * ... and save this in a standard form. |
| */ |
| mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_PHYSMEM, 1 ); |
| if (!mem) { |
| snmp_log_perror("No Physical Memory info entry"); |
| } else { |
| if (!mem->descr) |
| mem->descr = strdup("Physical memory"); |
| mem->units = pagesize; |
| mem->size = phys_mem/pagesize; |
| #if !defined(VM_TOTAL) |
| mem->free = free_mem; |
| #else |
| mem->free = total.t_free; |
| #endif |
| } |
| |
| mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_USERMEM, 1 ); |
| if (!mem) { |
| snmp_log_perror("No (user) Memory info entry"); |
| } else { |
| if (!mem->descr) |
| mem->descr = strdup("Real memory"); |
| mem->units = pagesize; |
| #if !defined(VM_TOTAL) |
| mem->size = user_mem/pagesize; |
| mem->free = free_mem; |
| #else |
| mem->size = total.t_rm; |
| mem->free = total.t_rm - total.t_arm; |
| #endif |
| } |
| |
| mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_VIRTMEM, 1 ); |
| if (!mem) { |
| snmp_log_perror("No Virtual Memory info entry"); |
| } else { |
| if (!mem->descr) |
| mem->descr = strdup("Virtual memory"); |
| mem->units = pagesize; |
| #if !defined(VM_TOTAL) |
| mem->size = mem_pages+swapTotal; |
| mem->free = free_mem+swapFree; |
| #else |
| mem->size = total.t_vm; |
| mem->free = total.t_vm - total.t_avm; |
| #endif |
| } |
| |
| #if defined(VM_TOTAL) |
| mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_SHARED, 1 ); |
| if (!mem) { |
| snmp_log_perror("No Shared Memory info entry"); |
| } else { |
| if (!mem->descr) |
| mem->descr = strdup("Shared virtual memory"); |
| mem->units = pagesize; |
| mem->size = total.t_vmshr; |
| mem->free = total.t_vmshr - total.t_avmshr; |
| } |
| |
| mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_SHARED2, 1 ); |
| if (!mem) { |
| snmp_log_perror("No Shared2 Memory info entry"); |
| } else { |
| if (!mem->descr) |
| mem->descr = strdup("Shared real memory"); |
| mem->units = pagesize; |
| mem->size = total.t_rmshr; |
| mem->free = total.t_rmshr - total.t_armshr; |
| } |
| #endif |
| |
| mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_CACHED, 1 ); |
| if (!mem) { |
| snmp_log_perror("No Cached Memory info entry"); |
| } else { |
| if (!mem->descr) |
| mem->descr = strdup("Cached memory"); |
| mem->units = pagesize; |
| mem->size = cache_count; |
| mem->free = 0; |
| } |
| |
| nswap = swapmode(pagesize); |
| mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_SWAP, 1 ); |
| if (!mem) { |
| snmp_log_perror("No Swap info entry"); |
| } else { |
| if (!mem->descr) |
| mem->descr = strdup( (nswap>1) ? "Swap space (total)" |
| : "Swap space"); |
| mem->units = pagesize; |
| mem->size = swapTotal; |
| mem->free = swapFree; |
| } |
| |
| mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_MBUF, 1 ); |
| if (!mem) { |
| snmp_log_perror("No Buffer, etc info entry"); |
| } else { |
| if (!mem->descr) |
| mem->descr = strdup("Memory buffers"); |
| mem->units = 1024; |
| mem->size = maxbufspace / 1024; |
| mem->free = (maxbufspace - bufspace)/1024; |
| } |
| |
| return 0; |
| } |
| |
| |
| |
| /* |
| * Retained from UCD implementation |
| */ |
| |
| |
| #ifndef freebsd4 |
| /* |
| * Executes swapinfo and parses last line |
| * This is just way too ugly ;) |
| */ |
| |
| static int |
| swapmode(long pagesize) |
| { |
| struct extensible ext; |
| int fd; |
| FILE *file; |
| |
| strcpy(ext.command, "/usr/sbin/swapinfo -k"); |
| |
| if ((fd = get_exec_output(&ext)) != -1) { |
| file = fdopen(fd, "r"); |
| |
| while (fgets(ext.output, sizeof(ext.output), file) != NULL); |
| |
| fclose(file); |
| wait_on_exec(&ext); |
| |
| sscanf(ext.output, "%*s%*d%qd%qd", &swapUsed, &swapFree); |
| |
| swapTotal = swapUsed + swapFree; |
| } |
| return 1; |
| } |
| #else |
| /* |
| * swapmode is based on a program called swapinfo written |
| * by Kevin Lahey <kml@rokkaku.atl.ga.us>. |
| */ |
| |
| #include <sys/conf.h> |
| |
| extern kvm_t *kd; |
| |
| static int |
| swapmode(long pagesize) |
| { |
| int i, n; |
| struct kvm_swap kswap[16]; |
| netsnmp_memory_info *mem; |
| char buf[1024]; |
| |
| n = kvm_getswapinfo(kd, kswap, sizeof(kswap) / sizeof(kswap[0]), 0); |
| |
| swapUsed = swapTotal = swapFree = 0; |
| |
| if ( n > 0 ) { |
| /* |
| * If there are multiple swap devices, then record |
| * the statistics for each one separately... |
| */ |
| for (i = 0; i < n; ++i) { |
| mem = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_SWAP+1+i, 1 ); |
| if (!mem) |
| continue; |
| if (!mem->descr) { |
| sprintf(buf, "swap %s", kswap[i].ksw_devname); |
| mem->descr = strdup( buf ); |
| } |
| mem->units = pagesize; |
| mem->size = kswap[i].ksw_total; |
| mem->free = kswap[i].ksw_total - kswap[i].ksw_used; |
| /* |
| * ... and keep a running total for the overall swap stats |
| */ |
| swapTotal += kswap[i].ksw_total; |
| swapUsed += kswap[i].ksw_used; |
| } |
| } else { |
| /* |
| * If there's only one swap device, then don't bother |
| * with individual statistics. |
| */ |
| swapTotal += kswap[0].ksw_total; |
| swapUsed += kswap[0].ksw_used; |
| } |
| |
| swapFree = swapTotal - swapUsed; |
| return n; |
| } |
| #endif |
| |