]> arthur.barton.de Git - netdata.git/blob - src/freebsd_sysctl.c
Merge pull request #1419 from vlvkobal/master
[netdata.git] / src / freebsd_sysctl.c
1 #include "common.h"
2
3 #ifndef __APPLE__
4 // NEEDED BY: struct vmtotal, struct vmmeter
5 #include <sys/vmmeter.h>
6 // NEEDED BY: struct devstat
7 #include <sys/devicestat.h>
8 // NEEDED BY: struct xswdev
9 #include <vm/vm_param.h>
10 // NEEDED BY: struct semid_kernel, struct shmid_kernel, struct msqid_kernel
11 #define _KERNEL
12 #include <sys/sem.h>
13 #include <sys/shm.h>
14 #include <sys/msg.h>
15 #undef _KERNEL
16 // NEEDED BY: struct sysctl_netisr_workstream, struct sysctl_netisr_work
17 #include <net/netisr.h>
18 // NEEDED BY: struct ifaddrs, getifaddrs()
19 #define _IFI_OQDROPS // It is for FreeNAS only. Most probably in future releases of FreeNAS it will be removed
20 #include <net/if.h>
21 #include <ifaddrs.h>
22 #endif /* __APPLE__ */
23 // NEEDED BY: do_disk_io
24 #define RRD_TYPE_DISK "disk"
25
26 // FreeBSD calculates load averages once every 5 seconds
27 #define MIN_LOADAVG_UPDATE_EVERY 5
28
29 // NEEDED BY: do_bandwidth
30 #define IFA_DATA(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s)
31
32 int do_freebsd_sysctl(int update_every, usec_t dt) {
33     (void)dt;
34
35     static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1,
36         do_loadavg = -1, do_all_processes = -1, do_disk_io = -1, do_swap = -1, do_ram = -1, do_swapio = -1,
37         do_pgfaults = -1, do_committed = -1, do_ipc_semaphores = -1, do_ipc_shared_mem = -1, do_ipc_msg_queues = -1,
38         do_dev_intr = -1, do_soft_intr = -1, do_netisr = -1, do_netisr_per_core = -1, do_bandwidth = -1;
39
40     if (unlikely(do_cpu == -1)) {
41         do_cpu                  = config_get_boolean("plugin:freebsd:sysctl", "cpu utilization", 1);
42         do_cpu_cores            = config_get_boolean("plugin:freebsd:sysctl", "per cpu core utilization", 1);
43         do_interrupts           = config_get_boolean("plugin:freebsd:sysctl", "cpu interrupts", 1);
44         do_dev_intr             = config_get_boolean("plugin:freebsd:sysctl", "device interrupts", 1);
45         do_soft_intr            = config_get_boolean("plugin:freebsd:sysctl", "software interrupts", 1);
46         do_context              = config_get_boolean("plugin:freebsd:sysctl", "context switches", 1);
47         do_forks                = config_get_boolean("plugin:freebsd:sysctl", "processes started", 1);
48         do_processes            = config_get_boolean("plugin:freebsd:sysctl", "processes running", 1);
49         do_loadavg              = config_get_boolean("plugin:freebsd:sysctl", "enable load average", 1);
50         do_all_processes        = config_get_boolean("plugin:freebsd:sysctl", "enable total processes", 1);
51         do_disk_io              = config_get_boolean("plugin:freebsd:sysctl", "stats for all disks", 1);
52         do_swap                 = config_get_boolean("plugin:freebsd:sysctl", "system swap", 1);
53         do_ram                  = config_get_boolean("plugin:freebsd:sysctl", "system ram", 1);
54         do_swapio               = config_get_boolean("plugin:freebsd:sysctl", "swap i/o", 1);
55         do_pgfaults             = config_get_boolean("plugin:freebsd:sysctl", "memory page faults", 1);
56         do_committed            = config_get_boolean("plugin:freebsd:sysctl", "committed memory", 1);
57         do_ipc_semaphores       = config_get_boolean("plugin:freebsd:sysctl", "ipc semaphores", 1);
58         do_ipc_shared_mem       = config_get_boolean("plugin:freebsd:sysctl", "ipc shared memory", 1);
59         do_ipc_msg_queues       = config_get_boolean("plugin:freebsd:sysctl", "ipc message queues", 1);
60         do_netisr               = config_get_boolean("plugin:freebsd:sysctl", "netisr", 1);
61         do_netisr_per_core      = config_get_boolean("plugin:freebsd:sysctl", "netisr per core", 1);
62         do_bandwidth            = config_get_boolean("plugin:freebsd:sysctl", "bandwidth", 1);
63     }
64
65     RRDSET *st;
66
67     int system_pagesize = getpagesize(); // wouldn't it be better to get value directly from hw.pagesize?
68     int i, n;
69     int common_error = 0;
70     size_t size;
71
72     // NEEDED BY: do_loadavg
73     static usec_t last_loadavg_usec = 0;
74     struct loadavg sysload;
75
76 #ifndef __APPLE__
77     // NEEDED BY: do_cpu, do_cpu_cores
78     long cp_time[CPUSTATES];
79
80     // NEEDED BY: du_cpu_cores, do_netisr, do_netisr_per_core
81     int ncpus;
82
83     // NEEDED BY: do_cpu_cores
84     static long *pcpu_cp_time = NULL;
85     char cpuid[8]; // no more than 4 digits expected
86
87     // NEEDED BY: do_all_processes, do_processes
88     struct vmtotal vmtotal_data;
89
90     // NEEDED BY: do_context, do_forks
91     u_int u_int_data;
92
93     // NEEDED BY: do_interrupts
94     size_t intrcnt_size;
95     unsigned long nintr = 0;
96     static unsigned long *intrcnt = NULL;
97     unsigned long long totalintr = 0;
98
99     // NEEDED BY: do_disk_io
100     #define BINTIME_SCALE 5.42101086242752217003726400434970855712890625e-17 // this is 1000/2^64
101     int numdevs;
102     static void *devstat_data = NULL;
103     struct devstat *dstat;
104     struct cur_dstat {
105         collected_number duration_read_ms;
106         collected_number duration_write_ms;
107         collected_number busy_time_ms;
108     } cur_dstat;
109     struct prev_dstat {
110         collected_number bytes_read;
111         collected_number bytes_write;
112         collected_number operations_read;
113         collected_number operations_write;
114         collected_number duration_read_ms;
115         collected_number duration_write_ms;
116         collected_number busy_time_ms;
117     } prev_dstat;
118
119     // NEEDED BY: do_swap
120     size_t mibsize;
121     int mib[3]; // CTL_MAXNAME = 24 maximum mib components (sysctl.h)
122     struct xswdev xsw;
123     struct total_xsw {
124         collected_number bytes_used;
125         collected_number bytes_total;
126     } total_xsw = {0, 0};
127
128     // NEEDED BY: do_swapio, do_ram
129     struct vmmeter vmmeter_data;
130
131     // NEEDED BY: do_ram
132     int vfs_bufspace_count;
133
134     // NEEDED BY: do_ipc_semaphores
135     struct ipc_sem {
136         int semmni;
137         collected_number sets;
138         collected_number semaphores;
139     } ipc_sem = {0, 0, 0};
140     static struct semid_kernel *ipc_sem_data = NULL;
141
142     // NEEDED BY: do_ipc_shared_mem
143     struct ipc_shm {
144         u_long shmmni;
145         collected_number segs;
146         collected_number segsize;
147     } ipc_shm = {0, 0, 0};
148     static struct shmid_kernel *ipc_shm_data = NULL;
149
150     // NEEDED BY: do_ipc_msg_queues
151     struct ipc_msq {
152         int msgmni;
153         collected_number queues;
154         collected_number messages;
155         collected_number usedsize;
156         collected_number allocsize;
157     } ipc_msq = {0, 0, 0, 0, 0};
158     static struct msqid_kernel *ipc_msq_data = NULL;
159
160     // NEEDED BY: do_netisr, do_netisr_per_core
161     size_t netisr_workstream_size;
162     size_t netisr_work_size;
163     unsigned long num_netisr_workstreams = 0, num_netisr_works = 0;
164     static struct sysctl_netisr_workstream *netisr_workstream = NULL;
165     static struct sysctl_netisr_work *netisr_work = NULL;
166     static struct netisr_stats {
167         collected_number dispatched;
168         collected_number hybrid_dispatched;
169         collected_number qdrops;
170         collected_number queued;
171     } *netisr_stats = NULL;
172     char netstat_cpuid[21]; // no more than 4 digits expected
173
174     // NEEDED BY: do_bandwidth
175     struct ifaddrs *ifa, *ifap;
176     struct iftot {
177         u_long  ift_ibytes;
178         u_long  ift_obytes;
179     } iftot = {0, 0};
180
181     // --------------------------------------------------------------------
182
183 #endif /* __APPLE__ */
184     if (last_loadavg_usec <= dt) {
185         if (likely(do_loadavg)) {
186             if (unlikely(GETSYSCTL("vm.loadavg", sysload))) {
187                 do_loadavg = 0;
188                 error("DISABLED: system.load");
189             } else {
190
191                 st = rrdset_find_bytype("system", "load");
192                 if (unlikely(!st)) {
193                     st = rrdset_create("system", "load", NULL, "load", NULL, "System Load Average", "load", 100, (update_every < MIN_LOADAVG_UPDATE_EVERY) ? MIN_LOADAVG_UPDATE_EVERY : update_every, RRDSET_TYPE_LINE);
194                     rrddim_add(st, "load1", NULL, 1, 1000, RRDDIM_ABSOLUTE);
195                     rrddim_add(st, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
196                     rrddim_add(st, "load15", NULL, 1, 1000, RRDDIM_ABSOLUTE);
197                 }
198                 else rrdset_next(st);
199
200                 rrddim_set(st, "load1", (collected_number) ((double)sysload.ldavg[0] / sysload.fscale * 1000));
201                 rrddim_set(st, "load5", (collected_number) ((double)sysload.ldavg[1] / sysload.fscale * 1000));
202                 rrddim_set(st, "load15", (collected_number) ((double)sysload.ldavg[2] / sysload.fscale * 1000));
203                 rrdset_done(st);
204             }
205         }
206
207         last_loadavg_usec = st->update_every * USEC_PER_SEC;
208     }
209     else last_loadavg_usec -= dt;
210 #ifndef __APPLE__
211
212     // --------------------------------------------------------------------
213
214     if (likely(do_all_processes | do_processes | do_committed)) {
215         if (unlikely(GETSYSCTL("vm.vmtotal", vmtotal_data))) {
216             do_all_processes = 0;
217             error("DISABLED: system.active_processes");
218             do_processes = 0;
219             error("DISABLED: system.processes");
220             do_committed = 0;
221             error("DISABLED: mem.committed");
222         } else {
223             if (likely(do_all_processes)) {
224
225                 st = rrdset_find_bytype("system", "active_processes");
226                 if (unlikely(!st)) {
227                     st = rrdset_create("system", "active_processes", NULL, "processes", NULL, "System Active Processes", "processes", 750, update_every, RRDSET_TYPE_LINE);
228                     rrddim_add(st, "active", NULL, 1, 1, RRDDIM_ABSOLUTE);
229                 }
230                 else rrdset_next(st);
231
232                 rrddim_set(st, "active", (vmtotal_data.t_rq + vmtotal_data.t_dw + vmtotal_data.t_pw + vmtotal_data.t_sl + vmtotal_data.t_sw));
233                 rrdset_done(st);
234             }
235
236             // --------------------------------------------------------------------
237
238             if (likely(do_processes)) {
239
240                 st = rrdset_find_bytype("system", "processes");
241                 if (unlikely(!st)) {
242                     st = rrdset_create("system", "processes", NULL, "processes", NULL, "System Processes", "processes", 600, update_every, RRDSET_TYPE_LINE);
243
244                     rrddim_add(st, "running", NULL, 1, 1, RRDDIM_ABSOLUTE);
245                     rrddim_add(st, "blocked", NULL, -1, 1, RRDDIM_ABSOLUTE);
246                 }
247                 else rrdset_next(st);
248
249                 rrddim_set(st, "running", vmtotal_data.t_rq);
250                 rrddim_set(st, "blocked", (vmtotal_data.t_dw + vmtotal_data.t_pw));
251                 rrdset_done(st);
252             }
253
254             // --------------------------------------------------------------------
255
256             if (likely(do_committed)) {
257                 st = rrdset_find("mem.committed");
258                 if (unlikely(!st)) {
259                     st = rrdset_create("mem", "committed", NULL, "system", NULL, "Committed (Allocated) Memory", "MB", 5000, update_every, RRDSET_TYPE_AREA);
260                     st->isdetail = 1;
261
262                     rrddim_add(st, "Committed_AS", NULL, system_pagesize, 1024, RRDDIM_ABSOLUTE);
263                 }
264                 else rrdset_next(st);
265
266                 rrddim_set(st, "Committed_AS", vmtotal_data.t_rm);
267                 rrdset_done(st);
268             }
269         }
270     }
271
272     // --------------------------------------------------------------------
273
274     if (likely(do_cpu)) {
275         if (unlikely(CPUSTATES != 5)) {
276             error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
277             do_cpu = 0;
278             error("DISABLED: system.cpu");
279         } else {
280             if (unlikely(GETSYSCTL("kern.cp_time", cp_time))) {
281                 do_cpu = 0;
282                 error("DISABLED: system.cpu");
283             } else {
284
285                 st = rrdset_find_bytype("system", "cpu");
286                 if (unlikely(!st)) {
287                     st = rrdset_create("system", "cpu", NULL, "cpu", "system.cpu", "Total CPU utilization", "percentage", 100, update_every, RRDSET_TYPE_STACKED);
288
289                     rrddim_add(st, "user", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
290                     rrddim_add(st, "nice", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
291                     rrddim_add(st, "system", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
292                     rrddim_add(st, "interrupt", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
293                     rrddim_add(st, "idle", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
294                     rrddim_hide(st, "idle");
295                 }
296                 else rrdset_next(st);
297
298                 rrddim_set(st, "user", cp_time[0]);
299                 rrddim_set(st, "nice", cp_time[1]);
300                 rrddim_set(st, "system", cp_time[2]);
301                 rrddim_set(st, "interrupt", cp_time[3]);
302                 rrddim_set(st, "idle", cp_time[4]);
303                 rrdset_done(st);
304             }
305         }
306     }
307
308     // --------------------------------------------------------------------
309
310     if (likely(do_cpu_cores)) {
311         if (unlikely(CPUSTATES != 5)) {
312             error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
313             do_cpu_cores = 0;
314             error("DISABLED: cpu.cpuXX");
315         } else {
316             if (unlikely(GETSYSCTL("kern.smp.cpus", ncpus))) {
317                 do_cpu_cores = 0;
318                 error("DISABLED: cpu.cpuXX");
319             } else {
320                 pcpu_cp_time = reallocz(pcpu_cp_time, sizeof(cp_time) * ncpus);
321
322                 for (i = 0; i < ncpus; i++) {
323                     if (unlikely(getsysctl("kern.cp_times", pcpu_cp_time, sizeof(cp_time) * ncpus))) {
324                         do_cpu_cores = 0;
325                         error("DISABLED: cpu.cpuXX");
326                         break;
327                     }
328                     if (unlikely(ncpus > 9999)) {
329                         error("FREEBSD: There are more than 4 digits in cpu cores number");
330                         do_cpu_cores = 0;
331                         error("DISABLED: cpu.cpuXX");
332                         break;
333                     }
334                     snprintfz(cpuid, 8, "cpu%d", i);
335
336                     st = rrdset_find_bytype("cpu", cpuid);
337                     if (unlikely(!st)) {
338                         st = rrdset_create("cpu", cpuid, NULL, "utilization", "cpu.cpu", "Core utilization", "percentage", 1000, update_every, RRDSET_TYPE_STACKED);
339
340                         rrddim_add(st, "user", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
341                         rrddim_add(st, "nice", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
342                         rrddim_add(st, "system", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
343                         rrddim_add(st, "interrupt", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
344                         rrddim_add(st, "idle", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
345                         rrddim_hide(st, "idle");
346                     }
347                     else rrdset_next(st);
348
349                     rrddim_set(st, "user", pcpu_cp_time[i * 5 + 0]);
350                     rrddim_set(st, "nice", pcpu_cp_time[i * 5 + 1]);
351                     rrddim_set(st, "system", pcpu_cp_time[i * 5 + 2]);
352                     rrddim_set(st, "interrupt", pcpu_cp_time[i * 5 + 3]);
353                     rrddim_set(st, "idle", pcpu_cp_time[i * 5 + 4]);
354                     rrdset_done(st);
355                 }
356             }
357         }
358     }
359
360     // --------------------------------------------------------------------
361
362     if (likely(do_interrupts)) {
363         if (unlikely(sysctlbyname("hw.intrcnt", NULL, &intrcnt_size, NULL, 0) == -1)) {
364             error("FREEBSD: sysctl(hw.intrcnt...) failed: %s", strerror(errno));
365             do_interrupts = 0;
366             error("DISABLED: system.intr");
367         } else {
368             nintr = intrcnt_size / sizeof(u_long);
369             intrcnt = reallocz(intrcnt, nintr * sizeof(u_long));
370             if (unlikely(getsysctl("hw.intrcnt", intrcnt, nintr * sizeof(u_long)))){
371                 do_interrupts = 0;
372                 error("DISABLED: system.intr");
373             } else {
374                 for (i = 0; i < nintr; i++)
375                     totalintr += intrcnt[i];
376
377                 st = rrdset_find_bytype("system", "intr");
378                 if (unlikely(!st)) {
379                     st = rrdset_create("system", "intr", NULL, "interrupts", NULL, "Total Hardware Interrupts", "interrupts/s", 900, update_every, RRDSET_TYPE_LINE);
380                     st->isdetail = 1;
381
382                     rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
383                 }
384                 else rrdset_next(st);
385
386                 rrddim_set(st, "interrupts", totalintr);
387                 rrdset_done(st);
388             }
389         }
390     }
391
392     // --------------------------------------------------------------------
393
394     if (likely(do_dev_intr)) {
395         if (unlikely(GETSYSCTL("vm.stats.sys.v_intr", u_int_data))) {
396             do_dev_intr = 0;
397             error("DISABLED: system.dev_intr");
398         } else {
399
400             st = rrdset_find_bytype("system", "dev_intr");
401             if (unlikely(!st)) {
402                 st = rrdset_create("system", "dev_intr", NULL, "interrupts", NULL, "Device Interrupts", "interrupts/s", 1000, update_every, RRDSET_TYPE_LINE);
403
404                 rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
405             }
406             else rrdset_next(st);
407
408             rrddim_set(st, "interrupts", u_int_data);
409             rrdset_done(st);
410         }
411     }
412
413     // --------------------------------------------------------------------
414
415     if (likely(do_soft_intr)) {
416         if (unlikely(GETSYSCTL("vm.stats.sys.v_soft", u_int_data))) {
417             do_soft_intr = 0;
418             error("DISABLED: system.dev_intr");
419         } else {
420
421             st = rrdset_find_bytype("system", "soft_intr");
422             if (unlikely(!st)) {
423                 st = rrdset_create("system", "soft_intr", NULL, "interrupts", NULL, "Software Interrupts", "interrupts/s", 1100, update_every, RRDSET_TYPE_LINE);
424
425                 rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
426             }
427             else rrdset_next(st);
428
429             rrddim_set(st, "interrupts", u_int_data);
430             rrdset_done(st);
431         }
432     }
433
434     // --------------------------------------------------------------------
435
436     if (likely(do_context)) {
437         if (unlikely(GETSYSCTL("vm.stats.sys.v_swtch", u_int_data))) {
438             do_context = 0;
439             error("DISABLED: system.ctxt");
440         } else {
441
442             st = rrdset_find_bytype("system", "ctxt");
443             if (unlikely(!st)) {
444                 st = rrdset_create("system", "ctxt", NULL, "processes", NULL, "CPU Context Switches", "context switches/s", 800, update_every, RRDSET_TYPE_LINE);
445
446                 rrddim_add(st, "switches", NULL, 1, 1, RRDDIM_INCREMENTAL);
447             }
448             else rrdset_next(st);
449
450             rrddim_set(st, "switches", u_int_data);
451             rrdset_done(st);
452         }
453     }
454
455     // --------------------------------------------------------------------
456
457     if (likely(do_forks)) {
458         if (unlikely(GETSYSCTL("vm.stats.vm.v_forks", u_int_data))) {
459             do_forks = 0;
460             error("DISABLED: system.forks");
461         } else {
462
463             st = rrdset_find_bytype("system", "forks");
464             if (unlikely(!st)) {
465                 st = rrdset_create("system", "forks", NULL, "processes", NULL, "Started Processes", "processes/s", 700, update_every, RRDSET_TYPE_LINE);
466                 st->isdetail = 1;
467
468                 rrddim_add(st, "started", NULL, 1, 1, RRDDIM_INCREMENTAL);
469             }
470             else rrdset_next(st);
471
472             rrddim_set(st, "started", u_int_data);
473             rrdset_done(st);
474         }
475     }
476
477     // --------------------------------------------------------------------
478
479     if (likely(do_disk_io)) {
480         if (unlikely(GETSYSCTL("kern.devstat.numdevs", numdevs))) {
481             do_disk_io = 0;
482             error("DISABLED: disk.io");
483         } else {
484             devstat_data = reallocz(devstat_data, sizeof(long) + sizeof(struct devstat) * numdevs); // there is generation number before devstat structures
485             if (unlikely(getsysctl("kern.devstat.all", devstat_data, sizeof(long) + sizeof(struct devstat) * numdevs))) {
486                 do_disk_io = 0;
487                 error("DISABLED: disk.io");
488             } else {
489                 dstat = devstat_data + sizeof(long); // skip generation number
490                 collected_number total_disk_reads = 0;
491                 collected_number total_disk_writes = 0;
492
493                 for (i = 0; i < numdevs; i++) {
494                     if ((dstat[i].device_type == (DEVSTAT_TYPE_IF_SCSI | DEVSTAT_TYPE_DIRECT)) || (dstat[i].device_type == (DEVSTAT_TYPE_IF_IDE | DEVSTAT_TYPE_DIRECT))) {
495
496                         // --------------------------------------------------------------------
497
498                         st = rrdset_find_bytype(RRD_TYPE_DISK, dstat[i].device_name);
499                         if (unlikely(!st)) {
500                             st = rrdset_create(RRD_TYPE_DISK, dstat[i].device_name, NULL, dstat[i].device_name, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
501
502                             rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_INCREMENTAL);
503                             rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_INCREMENTAL);
504                         }
505                         else rrdset_next(st);
506
507                         total_disk_reads += dstat[i].bytes[DEVSTAT_READ];
508                         total_disk_writes += dstat[i].bytes[DEVSTAT_WRITE];
509                         prev_dstat.bytes_read = rrddim_set(st, "reads", dstat[i].bytes[DEVSTAT_READ]);
510                         prev_dstat.bytes_write = rrddim_set(st, "writes", dstat[i].bytes[DEVSTAT_WRITE]);
511                         rrdset_done(st);
512
513                         // --------------------------------------------------------------------
514
515                         st = rrdset_find_bytype("disk_ops", dstat[i].device_name);
516                         if (unlikely(!st)) {
517                             st = rrdset_create("disk_ops", dstat[i].device_name, NULL, dstat[i].device_name, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
518                             st->isdetail = 1;
519
520                             rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
521                             rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
522                         }
523                         else rrdset_next(st);
524
525                         prev_dstat.operations_read = rrddim_set(st, "reads", dstat[i].operations[DEVSTAT_READ]);
526                         prev_dstat.operations_write = rrddim_set(st, "writes", dstat[i].operations[DEVSTAT_WRITE]);
527                         rrdset_done(st);
528
529                         // --------------------------------------------------------------------
530
531                         st = rrdset_find_bytype("disk_qops", dstat[i].device_name);
532                         if (unlikely(!st)) {
533                             st = rrdset_create("disk_qops", dstat[i].device_name, NULL, dstat[i].device_name, "disk.qops", "Disk Current I/O Operations", "operations", 2002, update_every, RRDSET_TYPE_LINE);
534                             st->isdetail = 1;
535
536                             rrddim_add(st, "operations", NULL, 1, 1, RRDDIM_ABSOLUTE);
537                         }
538                         else rrdset_next(st);
539
540                         rrddim_set(st, "operations", dstat[i].start_count - dstat[i].end_count);
541                         rrdset_done(st);
542
543                         // --------------------------------------------------------------------
544
545                         st = rrdset_find_bytype("disk_util", dstat[i].device_name);
546                         if (unlikely(!st)) {
547                             st = rrdset_create("disk_util", dstat[i].device_name, NULL, dstat[i].device_name, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
548                             st->isdetail = 1;
549
550                             rrddim_add(st, "utilization", NULL, 1, 10, RRDDIM_INCREMENTAL);
551                         }
552                         else rrdset_next(st);
553
554                         cur_dstat.busy_time_ms = dstat[i].busy_time.sec * 1000 + dstat[i].busy_time.frac * BINTIME_SCALE;
555                         prev_dstat.busy_time_ms = rrddim_set(st, "utilization", cur_dstat.busy_time_ms);
556                         rrdset_done(st);
557
558                         // --------------------------------------------------------------------
559
560                         st = rrdset_find_bytype("disk_iotime", dstat[i].device_name);
561                         if (unlikely(!st)) {
562                             st = rrdset_create("disk_iotime", dstat[i].device_name, NULL, dstat[i].device_name, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
563                             st->isdetail = 1;
564
565                             rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
566                             rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
567                         }
568                         else rrdset_next(st);
569
570                         cur_dstat.duration_read_ms = dstat[i].duration[DEVSTAT_READ].sec * 1000 + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
571                         cur_dstat.duration_write_ms = dstat[i].duration[DEVSTAT_WRITE].sec * 1000 + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
572                         prev_dstat.duration_read_ms = rrddim_set(st, "reads", cur_dstat.duration_read_ms);
573                         prev_dstat.duration_write_ms = rrddim_set(st, "writes", cur_dstat.duration_write_ms);
574                         rrdset_done(st);
575
576                         // --------------------------------------------------------------------
577                         // calculate differential charts
578                         // only if this is not the first time we run
579
580                         if (likely(dt)) {
581
582                             // --------------------------------------------------------------------
583
584                             st = rrdset_find_bytype("disk_await", dstat[i].device_name);
585                             if (unlikely(!st)) {
586                                 st = rrdset_create("disk_await", dstat[i].device_name, NULL, dstat[i].device_name, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
587                                 st->isdetail = 1;
588
589                                 rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_ABSOLUTE);
590                                 rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_ABSOLUTE);
591                             }
592                             else rrdset_next(st);
593
594                             rrddim_set(st, "reads", (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) ? 
595                                 (cur_dstat.duration_read_ms - prev_dstat.duration_read_ms) / (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) : 0);
596                             rrddim_set(st, "writes", (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) ?
597                                 (cur_dstat.duration_write_ms - prev_dstat.duration_write_ms) / (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) : 0);
598                             rrdset_done(st);
599
600                             // --------------------------------------------------------------------
601
602                             st = rrdset_find_bytype("disk_avgsz", dstat[i].device_name);
603                             if (unlikely(!st)) {
604                                 st = rrdset_create("disk_avgsz", dstat[i].device_name, NULL, dstat[i].device_name, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
605                                 st->isdetail = 1;
606
607                                 rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_ABSOLUTE);
608                                 rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_ABSOLUTE);
609                             }
610                             else rrdset_next(st);
611
612                             rrddim_set(st, "reads", (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) ?
613                                 (dstat[i].bytes[DEVSTAT_READ] - prev_dstat.bytes_read) / (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) : 0);
614                             rrddim_set(st, "writes", (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) ?
615                                 (dstat[i].bytes[DEVSTAT_WRITE] - prev_dstat.bytes_write) / (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) : 0);
616                             rrdset_done(st);
617
618                             // --------------------------------------------------------------------
619
620                             st = rrdset_find_bytype("disk_svctm", dstat[i].device_name);
621                             if (unlikely(!st)) {
622                                 st = rrdset_create("disk_svctm", dstat[i].device_name, NULL, dstat[i].device_name, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
623                                 st->isdetail = 1;
624
625                                 rrddim_add(st, "svctm", NULL, 1, 1, RRDDIM_ABSOLUTE);
626                             }
627                             else rrdset_next(st);
628
629                             rrddim_set(st, "svctm", ((dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) + (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write)) ?
630                                 (cur_dstat.busy_time_ms - prev_dstat.busy_time_ms) / ((dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) + (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write)) : 0);
631                             rrdset_done(st);
632                         }
633                     }
634
635                     // --------------------------------------------------------------------
636
637                     st = rrdset_find_bytype("system", "io");
638                     if (unlikely(!st)) {
639                         st = rrdset_create("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA);
640                         rrddim_add(st, "in",  NULL,  1, 1024, RRDDIM_INCREMENTAL);
641                         rrddim_add(st, "out", NULL, -1, 1024, RRDDIM_INCREMENTAL);
642                     }
643                     else rrdset_next(st);
644
645                     rrddim_set(st, "in", total_disk_reads);
646                     rrddim_set(st, "out", total_disk_writes);
647                     rrdset_done(st);
648                 }
649             }
650         }
651     }
652
653     // --------------------------------------------------------------------
654
655
656     if (likely(do_swap)) {
657         mibsize = sizeof mib / sizeof mib[0];
658         if (unlikely(sysctlnametomib("vm.swap_info", mib, &mibsize) == -1)) {
659             error("FREEBSD: sysctl(%s...) failed: %s", "vm.swap_info", strerror(errno));
660             do_swap = 0;
661             error("DISABLED: disk.io");
662         } else {
663             for (i = 0; ; i++) {
664                 mib[mibsize] = i;
665                 size = sizeof(xsw);
666                 if (unlikely(sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1 )) {
667                     if (unlikely(errno != ENOENT)) {
668                         error("FREEBSD: sysctl(%s...) failed: %s", "vm.swap_info", strerror(errno));
669                         do_swap = 0;
670                         error("DISABLED: disk.io");
671                     } else {
672                         if (unlikely(size != sizeof(xsw))) {
673                             error("FREEBSD: sysctl(%s...) expected %lu, got %lu", "vm.swap_info", (unsigned long)sizeof(xsw), (unsigned long)size);
674                             do_swap = 0;
675                             error("DISABLED: disk.io");
676                         } else break;
677                     }
678                 }
679                 total_xsw.bytes_used += xsw.xsw_used * system_pagesize;
680                 total_xsw.bytes_total += xsw.xsw_nblks * system_pagesize;
681             }
682
683             if (likely(do_swap)) {
684                 st = rrdset_find("system.swap");
685                 if (unlikely(!st)) {
686                     st = rrdset_create("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201, update_every, RRDSET_TYPE_STACKED);
687                     st->isdetail = 1;
688
689                     rrddim_add(st, "free",    NULL, 1, 1048576, RRDDIM_ABSOLUTE);
690                     rrddim_add(st, "used",    NULL, 1, 1048576, RRDDIM_ABSOLUTE);
691                 }
692                 else rrdset_next(st);
693
694                 rrddim_set(st, "used", total_xsw.bytes_used);
695                 rrddim_set(st, "free", total_xsw.bytes_total - total_xsw.bytes_used);
696                 rrdset_done(st);
697             }
698         }
699     }
700
701     // --------------------------------------------------------------------
702
703     if (likely(do_ram)) {
704         if (unlikely(GETSYSCTL("vm.stats.vm.v_active_count",    vmmeter_data.v_active_count) ||
705                      GETSYSCTL("vm.stats.vm.v_inactive_count",  vmmeter_data.v_inactive_count) ||
706                      GETSYSCTL("vm.stats.vm.v_wire_count",      vmmeter_data.v_wire_count) ||
707                      GETSYSCTL("vm.stats.vm.v_cache_count",     vmmeter_data.v_cache_count) ||
708                      GETSYSCTL("vfs.bufspace",                  vfs_bufspace_count) ||
709                      GETSYSCTL("vm.stats.vm.v_free_count",      vmmeter_data.v_free_count))) {
710             do_swapio = 0;
711             error("DISABLED: system.swapio");
712         } else {
713             st = rrdset_find("system.ram");
714             if (unlikely(!st)) {
715                 st = rrdset_create("system", "ram", NULL, "ram", NULL, "System RAM", "MB", 200, update_every, RRDSET_TYPE_STACKED);
716
717                 rrddim_add(st, "active",    NULL, system_pagesize, 1024, RRDDIM_ABSOLUTE);
718                 rrddim_add(st, "inactive",  NULL, system_pagesize, 1024, RRDDIM_ABSOLUTE);
719                 rrddim_add(st, "wired",     NULL, system_pagesize, 1024, RRDDIM_ABSOLUTE);
720                 rrddim_add(st, "cache",     NULL, system_pagesize, 1024, RRDDIM_ABSOLUTE);
721                 rrddim_add(st, "buffers",   NULL, 1, 1024, RRDDIM_ABSOLUTE);
722                 rrddim_add(st, "free",      NULL, system_pagesize, 1024, RRDDIM_ABSOLUTE);
723             }
724             else rrdset_next(st);
725
726             rrddim_set(st, "active",    vmmeter_data.v_active_count);
727             rrddim_set(st, "inactive",  vmmeter_data.v_inactive_count);
728             rrddim_set(st, "wired",     vmmeter_data.v_wire_count);
729             rrddim_set(st, "cache",     vmmeter_data.v_cache_count);
730             rrddim_set(st, "buffers",   vfs_bufspace_count);
731             rrddim_set(st, "free",      vmmeter_data.v_free_count);
732             rrdset_done(st);
733         }
734     }
735
736     // --------------------------------------------------------------------
737
738     if (likely(do_swapio)) {
739         if (unlikely(GETSYSCTL("vm.stats.vm.v_swappgsin", vmmeter_data.v_swappgsin) || GETSYSCTL("vm.stats.vm.v_swappgsout", vmmeter_data.v_swappgsout))) {
740             do_swapio = 0;
741             error("DISABLED: system.swapio");
742         } else {
743             st = rrdset_find("system.swapio");
744             if (unlikely(!st)) {
745                 st = rrdset_create("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250, update_every, RRDSET_TYPE_AREA);
746
747                 rrddim_add(st, "in",  NULL, system_pagesize, 1024, RRDDIM_INCREMENTAL);
748                 rrddim_add(st, "out", NULL, -system_pagesize, 1024, RRDDIM_INCREMENTAL);
749             }
750             else rrdset_next(st);
751
752             rrddim_set(st, "in", vmmeter_data.v_swappgsin);
753             rrddim_set(st, "out", vmmeter_data.v_swappgsout);
754             rrdset_done(st);
755         }
756     }
757
758     // --------------------------------------------------------------------
759
760     if (likely(do_pgfaults)) {
761         if (unlikely(GETSYSCTL("vm.stats.vm.v_vm_faults",   vmmeter_data.v_vm_faults) ||
762                      GETSYSCTL("vm.stats.vm.v_io_faults",   vmmeter_data.v_io_faults) ||
763                      GETSYSCTL("vm.stats.vm.v_cow_faults",  vmmeter_data.v_cow_faults) ||
764                      GETSYSCTL("vm.stats.vm.v_cow_optim",   vmmeter_data.v_cow_optim) ||
765                      GETSYSCTL("vm.stats.vm.v_intrans",     vmmeter_data.v_intrans))) {
766             do_pgfaults = 0;
767             error("DISABLED: mem.pgfaults");
768         } else {
769             st = rrdset_find("mem.pgfaults");
770             if (unlikely(!st)) {
771                 st = rrdset_create("mem", "pgfaults", NULL, "system", NULL, "Memory Page Faults", "page faults/s", 500, update_every, RRDSET_TYPE_LINE);
772                 st->isdetail = 1;
773
774                 rrddim_add(st, "memory", NULL, 1, 1, RRDDIM_INCREMENTAL);
775                 rrddim_add(st, "io_requiring", NULL, 1, 1, RRDDIM_INCREMENTAL);
776                 rrddim_add(st, "cow", NULL, 1, 1, RRDDIM_INCREMENTAL);
777                 rrddim_add(st, "cow_optimized", NULL, 1, 1, RRDDIM_INCREMENTAL);
778                 rrddim_add(st, "in_transit", NULL, 1, 1, RRDDIM_INCREMENTAL);
779             }
780             else rrdset_next(st);
781
782             rrddim_set(st, "memory", vmmeter_data.v_vm_faults);
783             rrddim_set(st, "io_requiring", vmmeter_data.v_io_faults);
784             rrddim_set(st, "cow", vmmeter_data.v_cow_faults);
785             rrddim_set(st, "cow_optimized", vmmeter_data.v_cow_optim);
786             rrddim_set(st, "in_transit", vmmeter_data.v_intrans);
787             rrdset_done(st);
788         }
789     }
790
791     // --------------------------------------------------------------------
792
793     if (likely(do_ipc_semaphores)) {
794         if (unlikely(GETSYSCTL("kern.ipc.semmni", ipc_sem.semmni))) {
795             do_ipc_semaphores = 0;
796             error("DISABLED: system.ipc_semaphores");
797             error("DISABLED: system.ipc_semaphore_arrays");
798         } else {
799             ipc_sem_data = reallocz(ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni);
800             if (unlikely(getsysctl("kern.ipc.sema", ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni))) {
801                 do_ipc_semaphores = 0;
802                 error("DISABLED: system.ipc_semaphores");
803                 error("DISABLED: system.ipc_semaphore_arrays");
804             } else {
805                 for (i = 0; i < ipc_sem.semmni; i++) {
806                     if (unlikely(ipc_sem_data[i].u.sem_perm.mode & SEM_ALLOC)) {
807                         ipc_sem.sets += 1;
808                         ipc_sem.semaphores += ipc_sem_data[i].u.sem_nsems;
809                     }
810                 }
811
812                 // --------------------------------------------------------------------
813
814                 st = rrdset_find("system.ipc_semaphores");
815                 if (unlikely(!st)) {
816                     st = rrdset_create("system", "ipc_semaphores", NULL, "ipc semaphores", NULL, "IPC Semaphores", "semaphores", 1000, rrd_update_every, RRDSET_TYPE_AREA);
817                     rrddim_add(st, "semaphores", NULL, 1, 1, RRDDIM_ABSOLUTE);
818                 }
819                 else rrdset_next(st);
820
821                 rrddim_set(st, "semaphores", ipc_sem.semaphores);
822                 rrdset_done(st);
823
824                 // --------------------------------------------------------------------
825
826                 st = rrdset_find("system.ipc_semaphore_arrays");
827                 if (unlikely(!st)) {
828                     st = rrdset_create("system", "ipc_semaphore_arrays", NULL, "ipc semaphores", NULL, "IPC Semaphore Arrays", "arrays", 1000, rrd_update_every, RRDSET_TYPE_AREA);
829                     rrddim_add(st, "arrays", NULL, 1, 1, RRDDIM_ABSOLUTE);
830                 }
831                 else rrdset_next(st);
832
833                 rrddim_set(st, "arrays", ipc_sem.sets);
834                 rrdset_done(st);
835             }
836         }
837     }
838
839     // --------------------------------------------------------------------
840
841     if (likely(do_ipc_shared_mem)) {
842         if (unlikely(GETSYSCTL("kern.ipc.shmmni", ipc_shm.shmmni))) {
843             do_ipc_shared_mem = 0;
844             error("DISABLED: system.ipc_shared_mem_segs");
845             error("DISABLED: system.ipc_shared_mem_size");
846         } else {
847             ipc_shm_data = reallocz(ipc_shm_data, sizeof(struct shmid_kernel) * ipc_shm.shmmni);
848             if (unlikely(getsysctl("kern.ipc.shmsegs", ipc_shm_data, sizeof(struct shmid_kernel) * ipc_shm.shmmni))) {
849                 do_ipc_shared_mem = 0;
850                 error("DISABLED: system.ipc_shared_mem_segs");
851                 error("DISABLED: system.ipc_shared_mem_size");
852             } else {
853                 for (i = 0; i < ipc_shm.shmmni; i++) {
854                     if (unlikely(ipc_shm_data[i].u.shm_perm.mode & 0x0800)) {
855                         ipc_shm.segs += 1;
856                         ipc_shm.segsize += ipc_shm_data[i].u.shm_segsz;
857                     }
858                 }
859
860                 // --------------------------------------------------------------------
861
862                 st = rrdset_find("system.ipc_shared_mem_segs");
863                 if (unlikely(!st)) {
864                     st = rrdset_create("system", "ipc_shared_mem_segs", NULL, "ipc shared memory", NULL, "IPC Shared Memory Segments", "segments", 1000, rrd_update_every, RRDSET_TYPE_AREA);
865                     rrddim_add(st, "segments", NULL, 1, 1, RRDDIM_ABSOLUTE);
866                 }
867                 else rrdset_next(st);
868
869                 rrddim_set(st, "segments", ipc_shm.segs);
870                 rrdset_done(st);
871
872                 // --------------------------------------------------------------------
873
874                 st = rrdset_find("system.ipc_shared_mem_size");
875                 if (unlikely(!st)) {
876                     st = rrdset_create("system", "ipc_shared_mem_size", NULL, "ipc shared memory", NULL, "IPC Shared Memory Segments Size", "kilobytes", 1000, rrd_update_every, RRDSET_TYPE_AREA);
877                     rrddim_add(st, "allocated", NULL, 1, 1024, RRDDIM_ABSOLUTE);
878                 }
879                 else rrdset_next(st);
880
881                 rrddim_set(st, "allocated", ipc_shm.segsize);
882                 rrdset_done(st);
883             }
884         }
885     }
886
887     // --------------------------------------------------------------------
888
889     if (likely(do_ipc_msg_queues)) {
890         if (unlikely(GETSYSCTL("kern.ipc.msgmni", ipc_msq.msgmni))) {
891             do_ipc_msg_queues = 0;
892             error("DISABLED: system.ipc_msq_queues");
893             error("DISABLED: system.ipc_msq_messages");
894             error("DISABLED: system.ipc_msq_size");
895         } else {
896             ipc_msq_data = reallocz(ipc_msq_data, sizeof(struct msqid_kernel) * ipc_msq.msgmni);
897             if (unlikely(getsysctl("kern.ipc.msqids", ipc_msq_data, sizeof(struct msqid_kernel) * ipc_msq.msgmni))) {
898                 do_ipc_msg_queues = 0;
899                 error("DISABLED: system.ipc_msq_queues");
900                 error("DISABLED: system.ipc_msq_messages");
901                 error("DISABLED: system.ipc_msq_size");
902             } else {
903                 for (i = 0; i < ipc_msq.msgmni; i++) {
904                     if (unlikely(ipc_msq_data[i].u.msg_qbytes != 0)) {
905                         ipc_msq.queues += 1;
906                         ipc_msq.messages += ipc_msq_data[i].u.msg_qnum;
907                         ipc_msq.usedsize += ipc_msq_data[i].u.msg_cbytes;
908                         ipc_msq.allocsize += ipc_msq_data[i].u.msg_qbytes;
909                     }
910                 }
911
912                 // --------------------------------------------------------------------
913
914                 st = rrdset_find("system.ipc_msq_queues");
915                 if (unlikely(!st)) {
916                     st = rrdset_create("system", "ipc_msq_queues", NULL, "ipc message queues", NULL, "Number of IPC Message Queues", "queues", 990, rrd_update_every, RRDSET_TYPE_AREA);
917                     rrddim_add(st, "queues", NULL, 1, 1, RRDDIM_ABSOLUTE);
918                 }
919                 else rrdset_next(st);
920
921                 rrddim_set(st, "queues", ipc_msq.queues);
922                 rrdset_done(st);
923
924                 // --------------------------------------------------------------------
925
926                 st = rrdset_find("system.ipc_msq_messages");
927                 if (unlikely(!st)) {
928                     st = rrdset_create("system", "ipc_msq_messages", NULL, "ipc message queues", NULL, "Number of Messages in IPC Message Queues", "messages", 1000, rrd_update_every, RRDSET_TYPE_AREA);
929                     rrddim_add(st, "messages", NULL, 1, 1, RRDDIM_ABSOLUTE);
930                 }
931                 else rrdset_next(st);
932
933                 rrddim_set(st, "messages", ipc_msq.messages);
934                 rrdset_done(st);
935
936                 // --------------------------------------------------------------------
937
938                 st = rrdset_find("system.ipc_msq_size");
939                 if (unlikely(!st)) {
940                     st = rrdset_create("system", "ipc_msq_size", NULL, "ipc message queues", NULL, "Size of IPC Message Queues", "bytes", 1100, rrd_update_every, RRDSET_TYPE_LINE);
941                     rrddim_add(st, "allocated", NULL, 1, 1, RRDDIM_ABSOLUTE);
942                     rrddim_add(st, "used", NULL, 1, 1, RRDDIM_ABSOLUTE);
943                 }
944                 else rrdset_next(st);
945
946                 rrddim_set(st, "allocated", ipc_msq.allocsize);
947                 rrddim_set(st, "used", ipc_msq.usedsize);
948                 rrdset_done(st);
949
950             }
951         }
952     }
953
954     // --------------------------------------------------------------------
955
956     if (likely(do_netisr || do_netisr_per_core)) {
957         if (unlikely(GETSYSCTL("kern.smp.cpus", ncpus))) {
958             common_error = 1;
959         } else if (unlikely(ncpus > 9999)) {
960             error("FREEBSD: There are more than 4 digits in cpu cores number");
961             common_error = 1;
962         } else if (unlikely(sysctlbyname("net.isr.workstream", NULL, &netisr_workstream_size, NULL, 0) == -1)) {
963             error("FREEBSD: sysctl(net.isr.workstream...) failed: %s", strerror(errno));
964             common_error = 1;
965         } else if (unlikely(sysctlbyname("net.isr.work", NULL, &netisr_work_size, NULL, 0) == -1)) {
966             error("FREEBSD: sysctl(net.isr.work...) failed: %s", strerror(errno));
967             common_error = 1;
968         } else {
969             num_netisr_workstreams = netisr_workstream_size / sizeof(struct sysctl_netisr_workstream);
970             netisr_workstream = reallocz(netisr_workstream, num_netisr_workstreams * sizeof(struct sysctl_netisr_workstream));
971             if (unlikely(getsysctl("net.isr.workstream", netisr_workstream, num_netisr_workstreams * sizeof(struct sysctl_netisr_workstream)))){
972                 common_error = 1;
973             } else {
974                 num_netisr_works = netisr_work_size / sizeof(struct sysctl_netisr_work);
975                 netisr_work = reallocz(netisr_work, num_netisr_works * sizeof(struct sysctl_netisr_work));
976                 if (unlikely(getsysctl("net.isr.work", netisr_work, num_netisr_works * sizeof(struct sysctl_netisr_work)))){
977                     common_error = 1;
978                 }
979             }
980         }
981         if (unlikely(common_error)) {
982             do_netisr = 0;
983             error("DISABLED: system.softnet_stat");
984             do_netisr_per_core = 0;
985             error("DISABLED: system.cpuX_softnet_stat");
986             common_error = 0;
987         } else {
988             netisr_stats = reallocz(netisr_stats, (ncpus + 1) * sizeof(struct netisr_stats));
989             bzero(netisr_stats, (ncpus + 1) * sizeof(struct netisr_stats));
990             for (i = 0; i < num_netisr_workstreams; i++) {
991                 for (n = 0; n < num_netisr_works; n++) {
992                     if (netisr_workstream[i].snws_wsid == netisr_work[n].snw_wsid) {
993                         netisr_stats[netisr_workstream[i].snws_cpu].dispatched += netisr_work[n].snw_dispatched;
994                         netisr_stats[netisr_workstream[i].snws_cpu].hybrid_dispatched += netisr_work[n].snw_hybrid_dispatched;
995                         netisr_stats[netisr_workstream[i].snws_cpu].qdrops += netisr_work[n].snw_qdrops;
996                         netisr_stats[netisr_workstream[i].snws_cpu].queued += netisr_work[n].snw_queued;
997                     }
998                 }
999             }
1000             for (i = 0; i < ncpus; i++) {
1001                 netisr_stats[ncpus].dispatched += netisr_stats[i].dispatched;
1002                 netisr_stats[ncpus].hybrid_dispatched += netisr_stats[i].hybrid_dispatched;
1003                 netisr_stats[ncpus].qdrops += netisr_stats[i].qdrops;
1004                 netisr_stats[ncpus].queued += netisr_stats[i].queued;
1005             }
1006         }
1007     }
1008
1009     // --------------------------------------------------------------------
1010
1011     if (likely(do_netisr)) {
1012         st = rrdset_find_bytype("system", "softnet_stat");
1013         if (unlikely(!st)) {
1014             st = rrdset_create("system", "softnet_stat", NULL, "softnet_stat", NULL, "System softnet_stat", "events/s", 955, update_every, RRDSET_TYPE_LINE);
1015             rrddim_add(st, "dispatched", NULL, 1, 1, RRDDIM_INCREMENTAL);
1016             rrddim_add(st, "hybrid_dispatched", NULL, 1, 1, RRDDIM_INCREMENTAL);
1017             rrddim_add(st, "qdrops", NULL, 1, 1, RRDDIM_INCREMENTAL);
1018             rrddim_add(st, "queued", NULL, 1, 1, RRDDIM_INCREMENTAL);
1019         }
1020         else rrdset_next(st);
1021
1022         rrddim_set(st, "dispatched", netisr_stats[ncpus].dispatched);
1023         rrddim_set(st, "hybrid_dispatched", netisr_stats[ncpus].hybrid_dispatched);
1024         rrddim_set(st, "qdrops", netisr_stats[ncpus].qdrops);
1025         rrddim_set(st, "queued", netisr_stats[ncpus].queued);
1026         rrdset_done(st);
1027     }
1028
1029     // --------------------------------------------------------------------
1030
1031     if (likely(do_netisr_per_core)) {
1032         for (i = 0; i < ncpus ;i++) {
1033             snprintfz(netstat_cpuid, 21, "cpu%d_softnet_stat", i);
1034
1035             st = rrdset_find_bytype("cpu", netstat_cpuid);
1036             if (unlikely(!st)) {
1037                 st = rrdset_create("cpu", netstat_cpuid, NULL, "softnet_stat", NULL, "Per CPU netisr statistics", "events/s", 1101 + i, update_every, RRDSET_TYPE_LINE);
1038                 rrddim_add(st, "dispatched", NULL, 1, 1, RRDDIM_INCREMENTAL);
1039                 rrddim_add(st, "hybrid_dispatched", NULL, 1, 1, RRDDIM_INCREMENTAL);
1040                 rrddim_add(st, "qdrops", NULL, 1, 1, RRDDIM_INCREMENTAL);
1041                 rrddim_add(st, "queued", NULL, 1, 1, RRDDIM_INCREMENTAL);
1042             }
1043             else rrdset_next(st);
1044
1045             rrddim_set(st, "dispatched", netisr_stats[i].dispatched);
1046             rrddim_set(st, "hybrid_dispatched", netisr_stats[i].hybrid_dispatched);
1047             rrddim_set(st, "qdrops", netisr_stats[i].qdrops);
1048             rrddim_set(st, "queued", netisr_stats[i].queued);
1049             rrdset_done(st);
1050         }
1051     }
1052
1053     // --------------------------------------------------------------------
1054
1055     if (likely(do_bandwidth)) {
1056         if (unlikely(getifaddrs(&ifap))) {
1057             error("FREEBSD: getifaddrs()");
1058             do_bandwidth = 0;
1059             error("DISABLED: system.ipv4");
1060         } else {
1061             iftot.ift_ibytes = iftot.ift_obytes = 0;
1062             for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1063                 if (ifa->ifa_addr->sa_family != AF_INET)
1064                         continue;
1065                 iftot.ift_ibytes += IFA_DATA(ibytes);
1066                 iftot.ift_obytes += IFA_DATA(obytes);
1067             }
1068
1069             st = rrdset_find("system.ipv4");
1070             if (unlikely(!st)) {
1071                 st = rrdset_create("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
1072
1073                 rrddim_add(st, "InOctets", "received", 8, 1024, RRDDIM_INCREMENTAL);
1074                 rrddim_add(st, "OutOctets", "sent", -8, 1024, RRDDIM_INCREMENTAL);
1075             }
1076             else rrdset_next(st);
1077
1078             rrddim_set(st, "InOctets", iftot.ift_ibytes);
1079             rrddim_set(st, "OutOctets", iftot.ift_obytes);
1080             rrdset_done(st);
1081
1082             // --------------------------------------------------------------------
1083
1084             iftot.ift_ibytes = iftot.ift_obytes = 0;
1085             for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1086                 if (ifa->ifa_addr->sa_family != AF_INET6)
1087                         continue;
1088                 iftot.ift_ibytes += IFA_DATA(ibytes);
1089                 iftot.ift_obytes += IFA_DATA(obytes);
1090             }
1091
1092             st = rrdset_find("system.ipv6");
1093             if (unlikely(!st)) {
1094                 st = rrdset_create("system", "ipv6", NULL, "network", NULL, "IPv6 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
1095
1096                 rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
1097                 rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
1098             }
1099             else rrdset_next(st);
1100
1101             rrddim_set(st, "sent", iftot.ift_obytes);
1102             rrddim_set(st, "received", iftot.ift_ibytes);
1103             rrdset_done(st);
1104
1105             for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1106                 if (ifa->ifa_addr->sa_family != AF_LINK)
1107                         continue;
1108
1109                 // --------------------------------------------------------------------
1110
1111                 st = rrdset_find_bytype("net", ifa->ifa_name);
1112                 if (unlikely(!st)) {
1113                     st = rrdset_create("net", ifa->ifa_name, NULL, ifa->ifa_name, "net.net", "Bandwidth", "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA);
1114
1115                     rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
1116                     rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
1117                 }
1118                 else rrdset_next(st);
1119
1120                 rrddim_set(st, "received", IFA_DATA(ibytes));
1121                 rrddim_set(st, "sent", IFA_DATA(obytes));
1122                 rrdset_done(st);
1123
1124                 // --------------------------------------------------------------------
1125
1126                 st = rrdset_find_bytype("net_packets", ifa->ifa_name);
1127                 if (unlikely(!st)) {
1128                     st = rrdset_create("net_packets", ifa->ifa_name, NULL, ifa->ifa_name, "net.packets", "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE);
1129                     st->isdetail = 1;
1130
1131                     rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
1132                     rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
1133                     rrddim_add(st, "multicast_received", NULL, 1, 1, RRDDIM_INCREMENTAL);
1134                     rrddim_add(st, "multicast_sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
1135                 }
1136                 else rrdset_next(st);
1137
1138                 rrddim_set(st, "received", IFA_DATA(ipackets));
1139                 rrddim_set(st, "sent", IFA_DATA(opackets));
1140                 rrddim_set(st, "multicast_received", IFA_DATA(imcasts));
1141                 rrddim_set(st, "multicast_sent", IFA_DATA(omcasts));
1142                 rrdset_done(st);
1143
1144                 // --------------------------------------------------------------------
1145
1146                 st = rrdset_find_bytype("net_errors", ifa->ifa_name);
1147                 if (unlikely(!st)) {
1148                     st = rrdset_create("net_errors", ifa->ifa_name, NULL, ifa->ifa_name, "net.errors", "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE);
1149                     st->isdetail = 1;
1150
1151                     rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
1152                     rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
1153                 }
1154                 else rrdset_next(st);
1155
1156                 rrddim_set(st, "inbound", IFA_DATA(ierrors));
1157                 rrddim_set(st, "outbound", IFA_DATA(oerrors));
1158                 rrdset_done(st);
1159
1160                 // --------------------------------------------------------------------
1161
1162                 st = rrdset_find_bytype("net_drops", ifa->ifa_name);
1163                 if (unlikely(!st)) {
1164                     st = rrdset_create("net_drops", ifa->ifa_name, NULL, ifa->ifa_name, "net.drops", "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE);
1165                     st->isdetail = 1;
1166
1167                     rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
1168                     rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
1169                 }
1170                 else rrdset_next(st);
1171
1172                 rrddim_set(st, "inbound", IFA_DATA(iqdrops));
1173                 rrddim_set(st, "outbound", IFA_DATA(oqdrops));
1174                 rrdset_done(st);
1175
1176                 // --------------------------------------------------------------------
1177
1178                 st = rrdset_find_bytype("net_events", ifa->ifa_name);
1179                 if (unlikely(!st)) {
1180                     st = rrdset_create("net_events", ifa->ifa_name, NULL, ifa->ifa_name, "net.events", "Network Interface Events", "events/s", 7006, update_every, RRDSET_TYPE_LINE);
1181                     st->isdetail = 1;
1182
1183                     rrddim_add(st, "frames", NULL, 1, 1, RRDDIM_INCREMENTAL);
1184                     rrddim_add(st, "collisions", NULL, -1, 1, RRDDIM_INCREMENTAL);
1185                     rrddim_add(st, "carrier", NULL, -1, 1, RRDDIM_INCREMENTAL);
1186                 }
1187                 else rrdset_next(st);
1188
1189                 rrddim_set(st, "collisions", IFA_DATA(collisions));
1190                 rrdset_done(st);
1191             }
1192
1193             freeifaddrs(ifap);
1194         }
1195     }
1196 #endif /* __APPLE__ */
1197
1198     return 0;
1199 }