1 /*
2 * vmstat_netbsd1.c
3 */
4
5 #include <net-snmp/net-snmp-config.h>
6
7 /*
8 * Ripped from /usr/scr/usr.bin/vmstat/vmstat.c (covering all bases)
9 */
10 #include <sys/param.h>
11 #include <sys/time.h>
12 #include <sys/proc.h>
13 #include <sys/dkstat.h>
14 #include <sys/buf.h>
15 #include <sys/uio.h>
16 #include <sys/namei.h>
17 #include <sys/malloc.h>
18 #include <sys/signal.h>
19 #include <sys/fcntl.h>
20 #include <sys/ioctl.h>
21 #include <sys/sysctl.h>
22 #include <sys/vmmeter.h>
23 #include <sys/sched.h>
24
25 #if defined(HAVE_UVM_UVM_PARAM_H) && defined(HAVE_UVM_UVM_EXTERN_H)
26 #include <uvm/uvm_param.h>
27 #include <uvm/uvm_extern.h>
28 #elif defined(HAVE_VM_VM_PARAM_H) && defined(HAVE_VM_VM_EXTERN_H)
29 #include <vm/vm_param.h>
30 #include <vm/vm_extern.h>
31 #else
32 #error vmstat_netbsd1.c: Is this really a NetBSD system?
33 #endif
34
35 #include <time.h>
36 #include <nlist.h>
37 #include <kvm.h>
38 #include <errno.h>
39 #include <unistd.h>
40 #include <stdio.h>
41 #include <ctype.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <paths.h>
45 #include <limits.h>
46
47
48 #include <net-snmp/net-snmp-includes.h>
49 #include <net-snmp/agent/net-snmp-agent-includes.h>
50 #include <net-snmp/agent/auto_nlist.h>
51
52 #include "util_funcs/header_generic.h"
53 #include "vmstat.h"
54
55 /*
56 * CPU percentage
57 */
58 #define CPU_PRC 100
59 #define CPTIME_SYMBOL "cp_time"
60 #define BOOTTIME_SYMBOL "boottime"
61
62 FindVarMethod var_extensible_vmstat;
63
64 void
init_vmstat_netbsd1(void)65 init_vmstat_netbsd1(void)
66 {
67
68 struct variable2 extensible_vmstat_variables[] = {
69 {MIBINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
70 var_extensible_vmstat, 1, {MIBINDEX}},
71 {ERRORNAME, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY,
72 var_extensible_vmstat, 1, {ERRORNAME}},
73 {SWAPIN, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
74 var_extensible_vmstat, 1, {SWAPIN}},
75 {SWAPOUT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
76 var_extensible_vmstat, 1, {SWAPOUT}},
77 {IOSENT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
78 var_extensible_vmstat, 1, {IOSENT}},
79 {IORECEIVE, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
80 var_extensible_vmstat, 1, {IORECEIVE}},
81 {SYSINTERRUPTS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
82 var_extensible_vmstat, 1, {SYSINTERRUPTS}},
83 {SYSCONTEXT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
84 var_extensible_vmstat, 1, {SYSCONTEXT}},
85 {CPUUSER, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
86 var_extensible_vmstat, 1, {CPUUSER}},
87 {CPUSYSTEM, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
88 var_extensible_vmstat, 1, {CPUSYSTEM}},
89 {CPUIDLE, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
90 var_extensible_vmstat, 1, {CPUIDLE}},
91 {CPURAWUSER, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
92 var_extensible_vmstat, 1, {CPURAWUSER}},
93 {CPURAWNICE, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
94 var_extensible_vmstat, 1, {CPURAWNICE}},
95 {CPURAWSYSTEM, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
96 var_extensible_vmstat, 1, {CPURAWSYSTEM}},
97 {CPURAWIDLE, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
98 var_extensible_vmstat, 1, {CPURAWIDLE}},
99 {CPURAWKERNEL, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
100 var_extensible_vmstat, 1, {CPURAWKERNEL}},
101 {CPURAWINTR, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
102 var_extensible_vmstat, 1, {CPURAWINTR}},
103
104 /*
105 * Future use:
106 */
107 /*
108 * {ERRORFLAG, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
109 * var_extensible_vmstat, 1, {ERRORFLAG }},
110 * {ERRORMSG, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY,
111 * var_extensible_vmstat, 1, {ERRORMSG }}
112 */
113 };
114
115 /*
116 * Define the OID pointer to the top of the mib tree that we're
117 * registering underneath
118 */
119 oid vmstat_variables_oid[] = { NETSNMP_UCDAVIS_MIB, 11 };
120
121 /*
122 * register ourselves with the agent to handle our mib tree
123 */
124 REGISTER_MIB("ucd-snmp/vmstat", extensible_vmstat_variables, variable2,
125 vmstat_variables_oid);
126
127 }
128
129
130 long
getuptime(void)131 getuptime(void)
132 {
133 static time_t now, boottime;
134 time_t uptime;
135
136 if (boottime == 0)
137 auto_nlist(BOOTTIME_SYMBOL, (char *) &boottime, sizeof(boottime));
138
139 time(&now);
140 uptime = now - boottime;
141
142 return (uptime);
143 }
144
145 unsigned char *
var_extensible_vmstat(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)146 var_extensible_vmstat(struct variable *vp,
147 oid * name,
148 size_t * length,
149 int exact,
150 size_t * var_len, WriteMethod ** write_method)
151 {
152
153 int loop;
154
155 time_t time_new = getuptime();
156 static time_t time_old;
157 static time_t time_diff;
158
159 #if defined(KERN_CP_TIME)
160 static uint64_t cpu_old[CPUSTATES];
161 static uint64_t cpu_new[CPUSTATES];
162 static uint64_t cpu_diff[CPUSTATES];
163 static uint64_t cpu_total;
164 #elif defined(KERN_CPTIME)
165 static long cpu_old[CPUSTATES];
166 static long cpu_new[CPUSTATES];
167 static long cpu_diff[CPUSTATES];
168 static long cpu_total;
169 #else
170 static long cpu_old[CPUSTATES];
171 static long cpu_new[CPUSTATES];
172 static long cpu_diff[CPUSTATES];
173 static long cpu_total;
174 #endif
175 long cpu_sum;
176 double cpu_prc;
177
178 static struct uvmexp mem_old, mem_new;
179 int mem_mib[] = { CTL_VM, VM_UVMEXP };
180 size_t mem_size = sizeof(struct uvmexp);
181
182 static long long_ret;
183 static char errmsg[300];
184
185 long_ret = 0; /* set to 0 as default */
186
187 if (header_generic(vp, name, length, exact, var_len, write_method))
188 return (NULL);
189
190 /*
191 * Update structures (only if time has passed)
192 */
193 if (time_new != time_old) {
194 #ifdef KERN_CP_TIME
195 int mib[2] = { CTL_KERN, KERN_CP_TIME };
196 size_t ssize = sizeof(cpu_new);
197
198 if (sysctl(mib, 2, cpu_new, &ssize, NULL, 0) < 0)
199 memset(cpu_new, 0, sizeof(cpu_new));
200 #elif defined(KERN_CPTIME)
201 int mib[2] = { CTL_KERN, KERN_CPTIME };
202 size_t ssize = sizeof(cpu_new);
203
204 if (sysctl(mib, 2, cpu_new, &ssize, NULL, 0) < 0)
205 memset(cpu_new, 0, sizeof(cpu_new));
206 #else
207 /*
208 * CPU usage
209 */
210 auto_nlist(CPTIME_SYMBOL, (char *) cpu_new, sizeof(cpu_new));
211 #endif
212
213 time_diff = time_new - time_old;
214 time_old = time_new;
215
216 cpu_total = 0;
217
218 for (loop = 0; loop < CPUSTATES; loop++) {
219 cpu_diff[loop] = cpu_new[loop] - cpu_old[loop];
220 cpu_old[loop] = cpu_new[loop];
221 cpu_total += cpu_diff[loop];
222 }
223
224 if (cpu_total == 0)
225 cpu_total = 1;
226
227 /*
228 * Memory info
229 */
230 mem_old = mem_new;
231 sysctl(mem_mib, 2, &mem_new, &mem_size, NULL, 0);
232 }
233
234 /*
235 * Rate macro
236 */
237 #define rate(x) (((x)+ time_diff/2) / time_diff)
238
239 /*
240 * Page-to-kb macro
241 */
242 #define ptok(p) ((p) * (mem_new.pagesize >> 10))
243
244 switch (vp->magic) {
245 case MIBINDEX:
246 long_ret = 1;
247 return ((u_char *) (&long_ret));
248 case ERRORNAME: /* dummy name */
249 sprintf(errmsg, "systemStats");
250 *var_len = strlen(errmsg);
251 return ((u_char *) (errmsg));
252 case SWAPIN:
253 long_ret = ptok(mem_new.swapins - mem_old.swapins);
254 long_ret = rate(long_ret);
255 return ((u_char *) (&long_ret));
256 case SWAPOUT:
257 long_ret = ptok(mem_new.swapouts - mem_old.swapouts);
258 long_ret = rate(long_ret);
259 return ((u_char *) (&long_ret));
260 case IOSENT:
261 #if NETSNMP_NO_DUMMY_VALUES
262 return NULL;
263 #endif
264 long_ret = -1;
265 return ((u_char *) (&long_ret));
266 case IORECEIVE:
267 #if NETSNMP_NO_DUMMY_VALUES
268 return NULL;
269 #endif
270 long_ret = -1;
271 return ((u_char *) (&long_ret));
272 case SYSINTERRUPTS:
273 long_ret = rate(mem_new.intrs - mem_old.intrs);
274 return ((u_char *) (&long_ret));
275 case SYSCONTEXT:
276 long_ret = rate(mem_new.swtch - mem_old.swtch);
277 return ((u_char *) (&long_ret));
278 case CPUUSER:
279 cpu_sum = cpu_diff[CP_USER] + cpu_diff[CP_NICE];
280 cpu_prc = (float) cpu_sum / (float) cpu_total;
281 long_ret = cpu_prc * CPU_PRC;
282 return ((u_char *) (&long_ret));
283 case CPUSYSTEM:
284 cpu_sum = cpu_diff[CP_SYS] + cpu_diff[CP_INTR];
285 cpu_prc = (float) cpu_sum / (float) cpu_total;
286 long_ret = cpu_prc * CPU_PRC;
287 return ((u_char *) (&long_ret));
288 case CPUIDLE:
289 cpu_sum = cpu_diff[CP_IDLE];
290 cpu_prc = (float) cpu_sum / (float) cpu_total;
291 long_ret = cpu_prc * CPU_PRC;
292 return ((u_char *) (&long_ret));
293 case CPURAWUSER:
294 long_ret = cpu_new[CP_USER];
295 return ((u_char *) (&long_ret));
296 case CPURAWNICE:
297 long_ret = cpu_new[CP_NICE];
298 return ((u_char *) (&long_ret));
299 case CPURAWSYSTEM:
300 long_ret = cpu_new[CP_SYS] + cpu_new[CP_INTR];
301 return ((u_char *) (&long_ret));
302 case CPURAWIDLE:
303 long_ret = cpu_new[CP_IDLE];
304 return ((u_char *) (&long_ret));
305 case CPURAWKERNEL:
306 long_ret = cpu_new[CP_SYS];
307 return ((u_char *) (&long_ret));
308 case CPURAWINTR:
309 long_ret = cpu_new[CP_INTR];
310 return ((u_char *) (&long_ret));
311 /*
312 * reserved for future use
313 */
314 /*
315 * case ERRORFLAG:
316 * return((u_char *) (&long_ret));
317 * case ERRORMSG:
318 * return((u_char *) (&long_ret));
319 */
320 }
321 return NULL;
322 }
323