]> arthur.barton.de Git - netdata.git/blob - src/freebsd_sysctl.c
Minimize reallocz usage in FreeBSD plugin
[netdata.git] / src / freebsd_sysctl.c
1 #include "common.h"
2
3 #include <sys/vmmeter.h>
4 #include <sys/devicestat.h>
5 #include <sys/mount.h>
6 #include <vm/vm_param.h>
7
8 #define _KERNEL
9 #include <sys/sem.h>
10 #include <sys/shm.h>
11 #include <sys/msg.h>
12 #undef _KERNEL
13
14 #include <net/netisr.h>
15 #include <net/if.h>
16 #include <ifaddrs.h>
17
18 #include <netinet/ip.h>
19 #include <netinet/ip_var.h>
20 #include <netinet/ip_icmp.h>
21 #include <netinet/icmp_var.h>
22 #include <netinet6/ip6_var.h>
23 #include <netinet/icmp6.h>
24 #include <netinet/tcp_var.h>
25 #include <netinet/tcp_fsm.h>
26 #include <netinet/udp.h>
27 #include <netinet/udp_var.h>
28
29 // --------------------------------------------------------------------------------------------------------------------
30 // common definitions and variables
31
32 #define KILO_FACTOR 1024
33 #define MEGA_FACTOR 1048576     // 1024 * 1024
34 #define GIGA_FACTOR 1073741824  // 1024 * 1024 * 1024
35
36 #define MAX_INT_DIGITS 10 // maximum number of digits for int
37
38 int system_pagesize = PAGE_SIZE;
39 int number_of_cpus = 1;
40
41 // --------------------------------------------------------------------------------------------------------------------
42 // FreeBSD plugin initialization
43
44 int freebsd_plugin_init()
45 {
46     system_pagesize = getpagesize();
47     if (system_pagesize <= 0) {
48         error("FREEBSD: can't get system page size");
49         return 1;
50     }
51
52     if (unlikely(GETSYSCTL_BY_NAME("kern.smp.cpus", number_of_cpus))) {
53         error("FREEBSD: can't get number of cpus");
54         return 1;
55     }
56
57     if (unlikely(!number_of_cpus)) {
58         error("FREEBSD: wrong number of cpus");
59         return 1;
60     }
61
62     return 0;
63 }
64
65 // --------------------------------------------------------------------------------------------------------------------
66 // vm.loadavg
67
68 // FreeBSD calculates load averages once every 5 seconds
69 #define MIN_LOADAVG_UPDATE_EVERY 5
70
71 int do_vm_loadavg(int update_every, usec_t dt){
72     static usec_t next_loadavg_dt = 0;
73
74     if (next_loadavg_dt <= dt) {
75         static int mib[2] = {0, 0};
76         struct loadavg sysload;
77
78         if (unlikely(GETSYSCTL_SIMPLE("vm.loadavg", mib, sysload))) {
79             error("DISABLED: system.load chart");
80             error("DISABLED: vm.loadavg module");
81             return 1;
82         } else {
83
84             // --------------------------------------------------------------------
85
86             static RRDSET *st = NULL;
87             static RRDDIM *rd_load1 = NULL, *rd_load2 = NULL, *rd_load3 = NULL;
88
89             if (unlikely(!st)) {
90                 st = rrdset_create_localhost("system",
91                                              "load",
92                                              NULL,
93                                              "load",
94                                              NULL,
95                                              "System Load Average",
96                                              "load",
97                                              100,
98                                              (update_every < MIN_LOADAVG_UPDATE_EVERY) ?
99                                              MIN_LOADAVG_UPDATE_EVERY : update_every, RRDSET_TYPE_LINE
100                 );
101                 rd_load1 = rrddim_add(st, "load1", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
102                 rd_load2 = rrddim_add(st, "load5", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
103                 rd_load3 = rrddim_add(st, "load15", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
104             } else
105                 rrdset_next(st);
106
107             rrddim_set_by_pointer(st, rd_load1, (collected_number) ((double) sysload.ldavg[0] / sysload.fscale * 1000));
108             rrddim_set_by_pointer(st, rd_load2, (collected_number) ((double) sysload.ldavg[1] / sysload.fscale * 1000));
109             rrddim_set_by_pointer(st, rd_load3, (collected_number) ((double) sysload.ldavg[2] / sysload.fscale * 1000));
110             rrdset_done(st);
111
112             next_loadavg_dt = st->update_every * USEC_PER_SEC;
113         }
114     }
115     else
116         next_loadavg_dt -= dt;
117
118     return 0;
119 }
120
121 // --------------------------------------------------------------------------------------------------------------------
122 // vm.vmtotal
123
124 int do_vm_vmtotal(int update_every, usec_t dt) {
125     (void)dt;
126     static int do_all_processes = -1, do_processes = -1, do_committed = -1;
127
128     if (unlikely(do_all_processes == -1)) {
129         do_all_processes    = config_get_boolean("plugin:freebsd:vm.vmtotal", "enable total processes", 1);
130         do_processes        = config_get_boolean("plugin:freebsd:vm.vmtotal", "processes running", 1);
131         do_committed        = config_get_boolean("plugin:freebsd:vm.vmtotal", "committed memory", 1);
132     }
133
134     if (likely(do_all_processes | do_processes | do_committed)) {
135         static int mib[2] = {0, 0};
136         struct vmtotal vmtotal_data;
137
138         if (unlikely(GETSYSCTL_SIMPLE("vm.vmtotal", mib, vmtotal_data))) {
139             do_all_processes = 0;
140             error("DISABLED: system.active_processes chart");
141             do_processes = 0;
142             error("DISABLED: system.processes chart");
143             do_committed = 0;
144             error("DISABLED: mem.committed chart");
145             error("DISABLED: vm.vmtotal module");
146             return 1;
147         } else {
148
149             // --------------------------------------------------------------------
150
151             if (likely(do_all_processes)) {
152                 static RRDSET *st = NULL;
153                 static RRDDIM *rd = NULL;
154
155                 if (unlikely(!st)) {
156                     st = rrdset_create_localhost("system",
157                                                  "active_processes",
158                                                  NULL,
159                                                  "processes",
160                                                  NULL,
161                                                  "System Active Processes",
162                                                  "processes",
163                                                  750,
164                                                  update_every,
165                                                  RRDSET_TYPE_LINE
166                     );
167                     rd = rrddim_add(st, "active", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
168                 }
169                 else rrdset_next(st);
170
171                 rrddim_set_by_pointer(st, rd, (vmtotal_data.t_rq + vmtotal_data.t_dw + vmtotal_data.t_pw + vmtotal_data.t_sl + vmtotal_data.t_sw));
172                 rrdset_done(st);
173             }
174
175             // --------------------------------------------------------------------
176
177             if (likely(do_processes)) {
178                 static RRDSET *st = NULL;
179                 static RRDDIM *rd_running = NULL, *rd_blocked = NULL;
180
181                 if (unlikely(!st)) {
182                     st = rrdset_create_localhost("system",
183                                                  "processes",
184                                                  NULL,
185                                                  "processes",
186                                                  NULL,
187                                                  "System Processes",
188                                                  "processes",
189                                                  600,
190                                                  update_every,
191                                                  RRDSET_TYPE_LINE
192                     );
193
194                     rd_running = rrddim_add(st, "running", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
195                     rd_blocked = rrddim_add(st, "blocked", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
196                 }
197                 else rrdset_next(st);
198
199                 rrddim_set_by_pointer(st, rd_running, vmtotal_data.t_rq);
200                 rrddim_set_by_pointer(st, rd_blocked, (vmtotal_data.t_dw + vmtotal_data.t_pw));
201                 rrdset_done(st);
202             }
203
204             // --------------------------------------------------------------------
205
206             if (likely(do_committed)) {
207                 static RRDSET *st = NULL;
208                 static RRDDIM *rd = NULL;
209
210                 if (unlikely(!st)) {
211                     st = rrdset_create_localhost("mem",
212                                                  "committed",
213                                                  NULL,
214                                                  "system",
215                                                  NULL,
216                                                  "Committed (Allocated) Memory",
217                                                  "MB",
218                                                  5000,
219                                                  update_every,
220                                                  RRDSET_TYPE_AREA
221                     );
222                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
223
224                     rd = rrddim_add(st, "Committed_AS", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
225                 }
226                 else rrdset_next(st);
227
228                 rrddim_set_by_pointer(st, rd, vmtotal_data.t_rm);
229                 rrdset_done(st);
230             }
231         }
232     } else {
233         error("DISABLED: vm.vmtotal module");
234         return 1;
235     }
236
237     return 0;
238 }
239
240 // --------------------------------------------------------------------------------------------------------------------
241 // kern.cp_time
242
243 int do_kern_cp_time(int update_every, usec_t dt) {
244     (void)dt;
245
246     if (unlikely(CPUSTATES != 5)) {
247         error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
248         error("DISABLED: system.cpu chart");
249         error("DISABLED: kern.cp_time module");
250         return 1;
251     } else {
252         static int mib[2] = {0, 0};
253         long cp_time[CPUSTATES];
254
255         if (unlikely(GETSYSCTL_SIMPLE("kern.cp_time", mib, cp_time))) {
256             error("DISABLED: system.cpu chart");
257             error("DISABLED: kern.cp_time module");
258             return 1;
259         } else {
260
261             // --------------------------------------------------------------------
262
263             static RRDSET *st = NULL;
264             static RRDDIM *rd_nice = NULL, *rd_system = NULL, *rd_user = NULL, *rd_interrupt = NULL, *rd_idle = NULL;
265
266             if (unlikely(!st)) {
267                 st = rrdset_create_localhost("system",
268                                              "cpu",
269                                              NULL,
270                                              "cpu",
271                                              "system.cpu",
272                                              "Total CPU utilization",
273                                              "percentage",
274                                              100, update_every,
275                                              RRDSET_TYPE_STACKED
276                 );
277
278                 rd_nice         = rrddim_add(st, "nice", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
279                 rd_system       = rrddim_add(st, "system", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
280                 rd_user         = rrddim_add(st, "user", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
281                 rd_interrupt    = rrddim_add(st, "interrupt", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
282                 rd_idle         = rrddim_add(st, "idle", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
283                 rrddim_hide(st, "idle");
284             }
285             else rrdset_next(st);
286
287             rrddim_set_by_pointer(st, rd_nice, cp_time[1]);
288             rrddim_set_by_pointer(st, rd_system, cp_time[2]);
289             rrddim_set_by_pointer(st, rd_user, cp_time[0]);
290             rrddim_set_by_pointer(st, rd_interrupt, cp_time[3]);
291             rrddim_set_by_pointer(st, rd_idle, cp_time[4]);
292             rrdset_done(st);
293         }
294     }
295
296     return 0;
297 }
298
299 // --------------------------------------------------------------------------------------------------------------------
300 // kern.cp_times
301
302 int do_kern_cp_times(int update_every, usec_t dt) {
303     (void)dt;
304
305     if (unlikely(CPUSTATES != 5)) {
306         error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
307         error("DISABLED: cpu.cpuXX charts");
308         error("DISABLED: kern.cp_times module");
309         return 1;
310     } else {
311         static int mib[2] = {0, 0};
312         long cp_time[CPUSTATES];
313         static long *pcpu_cp_time = NULL;
314         static int old_number_of_cpus = 0;
315
316         if(unlikely(number_of_cpus != old_number_of_cpus))
317             pcpu_cp_time = reallocz(pcpu_cp_time, sizeof(cp_time) * number_of_cpus);
318         if (unlikely(GETSYSCTL_WSIZE("kern.cp_times", mib, pcpu_cp_time, sizeof(cp_time) * number_of_cpus))) {
319             error("DISABLED: cpu.cpuXX charts");
320             error("DISABLED: kern.cp_times module");
321             return 1;
322         } else {
323
324             // --------------------------------------------------------------------
325
326             int i;
327             static struct cpu_chart {
328                 char cpuid[MAX_INT_DIGITS + 4];
329                 RRDSET *st;
330                 RRDDIM *rd_user;
331                 RRDDIM *rd_nice;
332                 RRDDIM *rd_system;
333                 RRDDIM *rd_interrupt;
334                 RRDDIM *rd_idle;
335             } *all_cpu_charts = NULL;
336
337             if(unlikely(number_of_cpus > old_number_of_cpus)) {
338                 all_cpu_charts = reallocz(all_cpu_charts, sizeof(struct cpu_chart) * number_of_cpus);
339                 memset(&all_cpu_charts[old_number_of_cpus], 0, sizeof(struct cpu_chart) * (number_of_cpus - old_number_of_cpus));
340             }
341
342             for (i = 0; i < number_of_cpus; i++) {
343                 if (unlikely(!all_cpu_charts[i].st)) {
344                     snprintfz(all_cpu_charts[i].cpuid, MAX_INT_DIGITS, "cpu%d", i);
345                     all_cpu_charts[i].st = rrdset_create_localhost("cpu",
346                                                                    all_cpu_charts[i].cpuid,
347                                                                    NULL,
348                                                                    "utilization",
349                                                                    "cpu.cpu",
350                                                                    "Core utilization",
351                                                                    "percentage",
352                                                                    1000,
353                                                                    update_every,
354                                                                    RRDSET_TYPE_STACKED
355                     );
356
357                     all_cpu_charts[i].rd_nice       = rrddim_add(all_cpu_charts[i].st, "nice", NULL, 1, 1,
358                                                                  RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
359                     all_cpu_charts[i].rd_system     = rrddim_add(all_cpu_charts[i].st, "system", NULL, 1, 1,
360                                                                  RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
361                     all_cpu_charts[i].rd_user       = rrddim_add(all_cpu_charts[i].st, "user", NULL, 1, 1,
362                                                                  RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
363                     all_cpu_charts[i].rd_interrupt  = rrddim_add(all_cpu_charts[i].st, "interrupt", NULL, 1, 1,
364                                                                  RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
365                     all_cpu_charts[i].rd_idle       = rrddim_add(all_cpu_charts[i].st, "idle", NULL, 1, 1,
366                                                                  RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
367                     rrddim_hide(all_cpu_charts[i].st, "idle");
368                 } else rrdset_next(all_cpu_charts[i].st);
369
370                 rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_nice, pcpu_cp_time[i * 5 + 1]);
371                 rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_system, pcpu_cp_time[i * 5 + 2]);
372                 rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_user, pcpu_cp_time[i * 5 + 0]);
373                 rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_interrupt, pcpu_cp_time[i * 5 + 3]);
374                 rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_idle, pcpu_cp_time[i * 5 + 4]);
375                 rrdset_done(all_cpu_charts[i].st);
376             }
377         }
378
379         old_number_of_cpus = number_of_cpus;
380     }
381
382     return 0;
383 }
384
385 // --------------------------------------------------------------------------------------------------------------------
386 // hw.intrcnt
387
388 int do_hw_intcnt(int update_every, usec_t dt) {
389     (void)dt;
390     static int mib_hw_intrcnt[2] = {0, 0};
391     size_t intrcnt_size = sizeof(mib_hw_intrcnt);
392     unsigned long i;
393
394     if (unlikely(GETSYSCTL_SIZE("hw.intrcnt", mib_hw_intrcnt, intrcnt_size))) {
395         error("DISABLED: system.intr chart");
396         error("DISABLED: system.interrupts chart");
397         error("DISABLED: hw.intrcnt module");
398         return 1;
399     } else {
400         unsigned long nintr = 0;
401         static unsigned long old_nintr = 0;
402         static unsigned long *intrcnt = NULL;
403         unsigned long long totalintr = 0;
404
405         nintr = intrcnt_size / sizeof(u_long);
406         if (unlikely(nintr != old_nintr))
407             intrcnt = reallocz(intrcnt, nintr * sizeof(u_long));
408         if (unlikely(GETSYSCTL_WSIZE("hw.intrcnt", mib_hw_intrcnt, intrcnt, nintr * sizeof(u_long)))) {
409             error("DISABLED: system.intr chart");
410             error("DISABLED: system.interrupts chart");
411             error("DISABLED: hw.intrcnt module");
412             return 1;
413         } else {
414             for (i = 0; i < nintr; i++)
415                 totalintr += intrcnt[i];
416
417             // --------------------------------------------------------------------
418
419             static RRDSET *st_intr = NULL;
420             static RRDDIM *rd_intr = NULL;
421
422             if (unlikely(!st_intr)) {
423                 st_intr = rrdset_create_localhost("system",
424                                                   "intr",
425                                                   NULL,
426                                                   "interrupts",
427                                                   NULL,
428                                                   "Total Hardware Interrupts",
429                                                   "interrupts/s",
430                                                   900,
431                                                   update_every,
432                                                   RRDSET_TYPE_LINE
433                 );
434                 rrdset_flag_set(st_intr, RRDSET_FLAG_DETAIL);
435
436                 rd_intr = rrddim_add(st_intr, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
437             } else
438                 rrdset_next(st_intr);
439
440             rrddim_set_by_pointer(st_intr, rd_intr, totalintr);
441             rrdset_done(st_intr);
442
443             // --------------------------------------------------------------------
444
445             size_t size;
446             static int mib_hw_intrnames[2] = {0, 0};
447             static char *intrnames = NULL;
448
449             size = nintr * (MAXCOMLEN + 1);
450             if (unlikely(nintr != old_nintr))
451                 intrnames = reallocz(intrnames, size);
452             if (unlikely(GETSYSCTL_WSIZE("hw.intrnames", mib_hw_intrnames, intrnames, size))) {
453                 error("DISABLED: system.intr chart");
454                 error("DISABLED: system.interrupts chart");
455                 error("DISABLED: hw.intrcnt module");
456                 return 1;
457             } else {
458
459                 // --------------------------------------------------------------------
460
461                 static RRDSET *st_interrupts = NULL;
462                 RRDDIM *rd_interrupts = NULL;
463                 void *p;
464
465                 if (unlikely(!st_interrupts))
466                     st_interrupts = rrdset_create_localhost("system",
467                                                             "interrupts",
468                                                             NULL,
469                                                             "interrupts",
470                                                             NULL,
471                                                             "System interrupts",
472                                                             "interrupts/s",
473                                                             1000,
474                                                             update_every,
475                                                             RRDSET_TYPE_STACKED
476                     );
477                 else
478                     rrdset_next(st_interrupts);
479
480                 for (i = 0; i < nintr; i++) {
481                     p = intrnames + i * (MAXCOMLEN + 1);
482                     if (unlikely((intrcnt[i] != 0) && (*(char *) p != 0))) {
483                         rd_interrupts = rrddim_find(st_interrupts, p);
484                         if (unlikely(!rd_interrupts))
485                             rd_interrupts = rrddim_add(st_interrupts, p, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
486                         rrddim_set_by_pointer(st_interrupts, rd_interrupts, intrcnt[i]);
487                     }
488                 }
489                 rrdset_done(st_interrupts);
490             }
491         }
492
493         old_nintr = nintr;
494     }
495
496     return 0;
497 }
498
499 // --------------------------------------------------------------------------------------------------------------------
500 // vm.stats.sys.v_intr
501
502 int do_vm_stats_sys_v_intr(int update_every, usec_t dt) {
503     (void)dt;
504     static int mib[4] = {0, 0, 0, 0};
505     u_int int_number;
506
507     if (unlikely(GETSYSCTL_SIMPLE("vm.stats.sys.v_intr", mib, int_number))) {
508         error("DISABLED: system.dev_intr chart");
509         error("DISABLED: vm.stats.sys.v_intr module");
510         return 1;
511     } else {
512
513         // --------------------------------------------------------------------
514
515         static RRDSET *st = NULL;
516         static RRDDIM *rd = NULL;
517
518         if (unlikely(!st)) {
519             st = rrdset_create_localhost("system",
520                                          "dev_intr",
521                                          NULL,
522                                          "interrupts",
523                                          NULL,
524                                          "Device Interrupts",
525                                          "interrupts/s",
526                                          1000,
527                                          update_every,
528                                          RRDSET_TYPE_LINE
529             );
530
531             rd = rrddim_add(st, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
532         }
533         else rrdset_next(st);
534
535         rrddim_set_by_pointer(st, rd, int_number);
536         rrdset_done(st);
537     }
538
539     return 0;
540 }
541
542 // --------------------------------------------------------------------------------------------------------------------
543 // vm.stats.sys.v_soft
544
545 int do_vm_stats_sys_v_soft(int update_every, usec_t dt) {
546     (void)dt;
547     static int mib[4] = {0, 0, 0, 0};
548     u_int soft_intr_number;
549
550     if (unlikely(GETSYSCTL_SIMPLE("vm.stats.sys.v_soft", mib, soft_intr_number))) {
551         error("DISABLED: system.dev_intr chart");
552         error("DISABLED: vm.stats.sys.v_soft module");
553         return 1;
554     } else {
555
556         // --------------------------------------------------------------------
557
558         static RRDSET *st = NULL;
559         static RRDDIM *rd = NULL;
560
561         if (unlikely(!st)) {
562             st = rrdset_create_localhost("system",
563                                          "soft_intr",
564                                          NULL,
565                                          "interrupts",
566                                          NULL,
567                                          "Software Interrupts",
568                                          "interrupts/s",
569                                          1100,
570                                          update_every,
571                                          RRDSET_TYPE_LINE
572             );
573
574             rd = rrddim_add(st, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
575         }
576         else rrdset_next(st);
577
578         rrddim_set_by_pointer(st, rd, soft_intr_number);
579         rrdset_done(st);
580     }
581
582     return 0;
583 }
584
585 // --------------------------------------------------------------------------------------------------------------------
586 // vm.stats.sys.v_swtch
587
588 int do_vm_stats_sys_v_swtch(int update_every, usec_t dt) {
589     (void)dt;
590     static int mib[4] = {0, 0, 0, 0};
591     u_int ctxt_number;
592
593     if (unlikely(GETSYSCTL_SIMPLE("vm.stats.sys.v_swtch", mib, ctxt_number))) {
594         error("DISABLED: system.ctxt chart");
595         error("DISABLED: vm.stats.sys.v_swtch module");
596         return 1;
597     } else {
598
599         // --------------------------------------------------------------------
600
601         static RRDSET *st = NULL;
602         static RRDDIM *rd = NULL;
603
604         if (unlikely(!st)) {
605             st = rrdset_create_localhost("system",
606                                          "ctxt",
607                                          NULL,
608                                          "processes",
609                                          NULL,
610                                          "CPU Context Switches",
611                                          "context switches/s",
612                                          800,
613                                          update_every,
614                                          RRDSET_TYPE_LINE
615             );
616
617             rd = rrddim_add(st, "switches", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
618         }
619         else rrdset_next(st);
620
621         rrddim_set_by_pointer(st, rd, ctxt_number);
622         rrdset_done(st);
623     }
624
625     return 0;
626 }
627
628 // --------------------------------------------------------------------------------------------------------------------
629 // vm.stats.vm.v_forks
630
631 int do_vm_stats_sys_v_forks(int update_every, usec_t dt) {
632     (void)dt;
633     static int mib[4] = {0, 0, 0, 0};
634     u_int forks_number;
635
636     if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_forks", mib, forks_number))) {
637         error("DISABLED: system.forks chart");
638         error("DISABLED: vm.stats.sys.v_swtch module");
639         return 1;
640     } else {
641
642         // --------------------------------------------------------------------
643
644         static RRDSET *st = NULL;
645         static RRDDIM *rd = NULL;
646
647         if (unlikely(!st)) {
648             st = rrdset_create_localhost("system",
649                                          "forks",
650                                          NULL,
651                                          "processes",
652                                          NULL,
653                                          "Started Processes",
654                                          "processes/s",
655                                          700,
656                                          update_every,
657                                          RRDSET_TYPE_LINE
658             );
659
660             rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
661
662             rd = rrddim_add(st, "started", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
663         }
664         else rrdset_next(st);
665
666         rrddim_set_by_pointer(st, rd, forks_number);
667         rrdset_done(st);
668     }
669
670     return 0;
671 }
672
673 // --------------------------------------------------------------------------------------------------------------------
674 // vm.swap_info
675
676 int do_vm_swap_info(int update_every, usec_t dt) {
677     (void)dt;
678     static int mib[3] = {0, 0, 0};
679
680     if (unlikely(getsysctl_mib("vm.swap_info", mib, 2))) {
681         error("DISABLED: system.swap chart");
682         error("DISABLED: vm.swap_info module");
683         return 1;
684     } else {
685         int i;
686         struct xswdev xsw;
687         struct total_xsw {
688             collected_number bytes_used;
689             collected_number bytes_total;
690         } total_xsw = {0, 0};
691
692         for (i = 0; ; i++) {
693             size_t size;
694
695             mib[2] = i;
696             size = sizeof(xsw);
697             if (unlikely(sysctl(mib, 3, &xsw, &size, NULL, 0) == -1 )) {
698                 if (unlikely(errno != ENOENT)) {
699                     error("FREEBSD: sysctl(%s...) failed: %s", "vm.swap_info", strerror(errno));
700                     error("DISABLED: system.swap chart");
701                     error("DISABLED: vm.swap_info module");
702                     return 1;
703                 } else {
704                     if (unlikely(size != sizeof(xsw))) {
705                         error("FREEBSD: sysctl(%s...) expected %lu, got %lu", "vm.swap_info", (unsigned long)sizeof(xsw), (unsigned long)size);
706                         error("DISABLED: system.swap chart");
707                         error("DISABLED: vm.swap_info module");
708                         return 1;
709                     } else break;
710                 }
711             }
712             total_xsw.bytes_used += xsw.xsw_used;
713             total_xsw.bytes_total += xsw.xsw_nblks;
714         }
715
716         // --------------------------------------------------------------------
717
718         static RRDSET *st = NULL;
719         static RRDDIM *rd_free = NULL, *rd_used = NULL;
720
721         if (unlikely(!st)) {
722             st = rrdset_create_localhost("system",
723                                          "swap",
724                                          NULL,
725                                          "swap",
726                                          NULL,
727                                          "System Swap",
728                                          "MB",
729                                          201,
730                                          update_every,
731                                          RRDSET_TYPE_STACKED
732             );
733
734             rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
735
736             rd_free = rrddim_add(st, "free",    NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
737             rd_used = rrddim_add(st, "used",    NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
738         }
739         else rrdset_next(st);
740
741         rrddim_set_by_pointer(st, rd_free, total_xsw.bytes_total - total_xsw.bytes_used);
742         rrddim_set_by_pointer(st, rd_used, total_xsw.bytes_used);
743         rrdset_done(st);
744     }
745
746     return 0;
747 }
748
749 // --------------------------------------------------------------------------------------------------------------------
750 // system.ram
751
752 int do_system_ram(int update_every, usec_t dt) {
753     (void)dt;
754     static int mib_active_count[4] = {0, 0, 0, 0}, mib_inactive_count[4] = {0, 0, 0, 0}, mib_wire_count[4] = {0, 0, 0, 0},
755                mib_cache_count[4] = {0, 0, 0, 0}, mib_vfs_bufspace[2] = {0, 0}, mib_free_count[4] = {0, 0, 0, 0};
756     struct vmmeter vmmeter_data;
757     int vfs_bufspace_count;
758
759     if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_active_count",   mib_active_count,   vmmeter_data.v_active_count) ||
760                  GETSYSCTL_SIMPLE("vm.stats.vm.v_inactive_count", mib_inactive_count, vmmeter_data.v_inactive_count) ||
761                  GETSYSCTL_SIMPLE("vm.stats.vm.v_wire_count",     mib_wire_count,     vmmeter_data.v_wire_count) ||
762 #if __FreeBSD_version < 1200016
763                  GETSYSCTL_SIMPLE("vm.stats.vm.v_cache_count",    mib_cache_count,    vmmeter_data.v_cache_count) ||
764 #endif
765                  GETSYSCTL_SIMPLE("vfs.bufspace",                 mib_vfs_bufspace,     vfs_bufspace_count) ||
766                  GETSYSCTL_SIMPLE("vm.stats.vm.v_free_count",     mib_free_count,     vmmeter_data.v_free_count))) {
767         error("DISABLED: system.ram chart");
768         error("DISABLED: System.ram module");
769         return 1;
770     } else {
771
772         // --------------------------------------------------------------------
773
774         static RRDSET *st = NULL;
775         static RRDDIM *rd_free = NULL, *rd_active = NULL, *rd_inactive = NULL,
776                       *rd_wired = NULL, *rd_cache = NULL, *rd_buffers = NULL;
777
778         st = rrdset_find_localhost("system.ram");
779         if (unlikely(!st)) {
780             st = rrdset_create_localhost("system",
781                                          "ram",
782                                          NULL,
783                                          "ram",
784                                          NULL,
785                                          "System RAM",
786                                          "MB",
787                                          200,
788                                          update_every,
789                                          RRDSET_TYPE_STACKED
790             );
791
792             rd_free     = rrddim_add(st, "free",     NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
793             rd_active   = rrddim_add(st, "active",   NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
794             rd_inactive = rrddim_add(st, "inactive", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
795             rd_wired    = rrddim_add(st, "wired",    NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
796 #if __FreeBSD_version < 1200016
797             rd_cache    = rrddim_add(st, "cache",    NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
798 #endif
799             rd_buffers  = rrddim_add(st, "buffers",  NULL, 1, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
800         }
801         else rrdset_next(st);
802
803         rrddim_set_by_pointer(st, rd_free,     vmmeter_data.v_free_count);
804         rrddim_set_by_pointer(st, rd_active,   vmmeter_data.v_active_count);
805         rrddim_set_by_pointer(st, rd_inactive, vmmeter_data.v_inactive_count);
806         rrddim_set_by_pointer(st, rd_wired,    vmmeter_data.v_wire_count);
807 #if __FreeBSD_version < 1200016
808         rrddim_set_by_pointer(st, rd_cache,    vmmeter_data.v_cache_count);
809 #endif
810         rrddim_set_by_pointer(st, rd_buffers,  vfs_bufspace_count);
811         rrdset_done(st);
812     }
813
814     return 0;
815 }
816
817 // --------------------------------------------------------------------------------------------------------------------
818 // vm.stats.vm.v_swappgs
819
820 int do_vm_stats_sys_v_swappgs(int update_every, usec_t dt) {
821     (void)dt;
822     static int mib_swappgsin[4] = {0, 0, 0, 0}, mib_swappgsout[4] = {0, 0, 0, 0};
823     struct vmmeter vmmeter_data;
824
825     if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_swappgsin", mib_swappgsin, vmmeter_data.v_swappgsin) ||
826                  GETSYSCTL_SIMPLE("vm.stats.vm.v_swappgsout", mib_swappgsout, vmmeter_data.v_swappgsout))) {
827         error("DISABLED: system.swapio chart");
828         error("DISABLED: vm.stats.vm.v_swappgs module");
829         return 1;
830     } else {
831
832         // --------------------------------------------------------------------
833
834         static RRDSET *st = NULL;
835         static RRDDIM *rd_in = NULL, *rd_out = NULL;
836
837         if (unlikely(!st)) {
838             st = rrdset_create_localhost("system",
839                                          "swapio",
840                                          NULL,
841                                          "swap",
842                                          NULL,
843                                          "Swap I/O",
844                                          "kilobytes/s",
845                                          250,
846                                          update_every,
847                                          RRDSET_TYPE_AREA
848             );
849
850             rd_in = rrddim_add(st, "in",  NULL, system_pagesize, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
851             rd_out = rrddim_add(st, "out", NULL, -system_pagesize, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
852         }
853         else rrdset_next(st);
854
855         rrddim_set_by_pointer(st, rd_in, vmmeter_data.v_swappgsin);
856         rrddim_set_by_pointer(st, rd_out, vmmeter_data.v_swappgsout);
857         rrdset_done(st);
858     }
859
860     return 0;
861 }
862
863 // --------------------------------------------------------------------------------------------------------------------
864 // vm.stats.vm.v_pgfaults
865
866 int do_vm_stats_sys_v_pgfaults(int update_every, usec_t dt) {
867     (void)dt;
868     static int mib_vm_faults[4] = {0, 0, 0, 0}, mib_io_faults[4] = {0, 0, 0, 0}, mib_cow_faults[4] = {0, 0, 0, 0},
869                mib_cow_optim[4] = {0, 0, 0, 0}, mib_intrans[4] = {0, 0, 0, 0};
870     struct vmmeter vmmeter_data;
871
872     if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_vm_faults",  mib_vm_faults,  vmmeter_data.v_vm_faults) ||
873                  GETSYSCTL_SIMPLE("vm.stats.vm.v_io_faults",  mib_io_faults,  vmmeter_data.v_io_faults) ||
874                  GETSYSCTL_SIMPLE("vm.stats.vm.v_cow_faults", mib_cow_faults, vmmeter_data.v_cow_faults) ||
875                  GETSYSCTL_SIMPLE("vm.stats.vm.v_cow_optim",  mib_cow_optim,  vmmeter_data.v_cow_optim) ||
876                  GETSYSCTL_SIMPLE("vm.stats.vm.v_intrans",    mib_intrans,    vmmeter_data.v_intrans))) {
877         error("DISABLED: mem.pgfaults chart");
878         error("DISABLED: vm.stats.vm.v_pgfaults module");
879         return 1;
880     } else {
881
882         // --------------------------------------------------------------------
883
884         static RRDSET *st = NULL;
885         static RRDDIM *rd_memory = NULL, *rd_io_requiring = NULL, *rd_cow = NULL,
886                       *rd_cow_optimized = NULL, *rd_in_transit = NULL;
887
888         if (unlikely(!st)) {
889             st = rrdset_create_localhost("mem",
890                                          "pgfaults",
891                                          NULL,
892                                          "system",
893                                          NULL,
894                                          "Memory Page Faults",
895                                          "page faults/s",
896                                          500,
897                                          update_every,
898                                          RRDSET_TYPE_LINE
899             );
900
901             rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
902
903             rd_memory        = rrddim_add(st, "memory",        NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
904             rd_io_requiring  = rrddim_add(st, "io_requiring",  NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
905             rd_cow           = rrddim_add(st, "cow",           NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
906             rd_cow_optimized = rrddim_add(st, "cow_optimized", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
907             rd_in_transit    = rrddim_add(st, "in_transit",    NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
908         }
909         else rrdset_next(st);
910
911         rrddim_set_by_pointer(st, rd_memory,        vmmeter_data.v_vm_faults);
912         rrddim_set_by_pointer(st, rd_io_requiring,  vmmeter_data.v_io_faults);
913         rrddim_set_by_pointer(st, rd_cow,           vmmeter_data.v_cow_faults);
914         rrddim_set_by_pointer(st, rd_cow_optimized, vmmeter_data.v_cow_optim);
915         rrddim_set_by_pointer(st, rd_in_transit,    vmmeter_data.v_intrans);
916         rrdset_done(st);
917     }
918
919     return 0;
920 }
921
922 // --------------------------------------------------------------------------------------------------------------------
923 // kern.ipc.sem
924
925 int do_kern_ipc_sem(int update_every, usec_t dt) {
926     (void)dt;
927     static int mib_semmni[3] = {0, 0, 0}, mib_sema[3] = {0, 0, 0};
928     struct ipc_sem {
929         int semmni;
930         collected_number sets;
931         collected_number semaphores;
932     } ipc_sem = {0, 0, 0};
933
934     if (unlikely(GETSYSCTL_SIMPLE("kern.ipc.semmni", mib_semmni, ipc_sem.semmni))) {
935         error("DISABLED: system.ipc_semaphores chart");
936         error("DISABLED: system.ipc_semaphore_arrays chart");
937         error("DISABLED: kern.ipc.sem module");
938         return 1;
939     } else {
940         static struct semid_kernel *ipc_sem_data = NULL;
941         static int old_semmni = 0;
942
943         if (unlikely(ipc_sem.semmni != old_semmni)) {
944             ipc_sem_data = reallocz(ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni);
945             old_semmni = ipc_sem.semmni;
946         }
947         if (unlikely(GETSYSCTL_WSIZE("kern.ipc.sema", mib_sema, ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni))) {
948             error("DISABLED: system.ipc_semaphores chart");
949             error("DISABLED: system.ipc_semaphore_arrays chart");
950             error("DISABLED: kern.ipc.sem module");
951             return 1;
952         } else {
953             int i;
954
955             for (i = 0; i < ipc_sem.semmni; i++) {
956                 if (unlikely(ipc_sem_data[i].u.sem_perm.mode & SEM_ALLOC)) {
957                     ipc_sem.sets += 1;
958                     ipc_sem.semaphores += ipc_sem_data[i].u.sem_nsems;
959                 }
960             }
961
962             // --------------------------------------------------------------------
963
964             static RRDSET *st_semaphores = NULL, *st_semaphore_arrays = NULL;
965             static RRDDIM *rd_semaphores = NULL, *rd_semaphore_arrays = NULL;
966
967             if (unlikely(!st_semaphores)) {
968                 st_semaphores = rrdset_create_localhost("system",
969                                                         "ipc_semaphores",
970                                                         NULL,
971                                                         "ipc semaphores",
972                                                         NULL,
973                                                         "IPC Semaphores",
974                                                         "semaphores",
975                                                         1000,
976                                                         update_every,
977                                                         RRDSET_TYPE_AREA
978                 );
979
980                 rd_semaphores = rrddim_add(st_semaphores, "semaphores", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
981             }
982             else rrdset_next(st_semaphores);
983
984             rrddim_set_by_pointer(st_semaphores, rd_semaphores, ipc_sem.semaphores);
985             rrdset_done(st_semaphores);
986
987             // --------------------------------------------------------------------
988
989             if (unlikely(!st_semaphore_arrays)) {
990                 st_semaphore_arrays = rrdset_create_localhost("system",
991                                                               "ipc_semaphore_arrays",
992                                                               NULL,
993                                                               "ipc semaphores",
994                                                               NULL,
995                                                               "IPC Semaphore Arrays",
996                                                               "arrays",
997                                                               1000,
998                                                               update_every,
999                                                               RRDSET_TYPE_AREA
1000                 );
1001
1002                 rd_semaphore_arrays = rrddim_add(st_semaphore_arrays, "arrays", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1003             }
1004             else rrdset_next(st_semaphore_arrays);
1005
1006             rrddim_set_by_pointer(st_semaphore_arrays, rd_semaphore_arrays, ipc_sem.sets);
1007             rrdset_done(st_semaphore_arrays);
1008         }
1009     }
1010
1011     return 0;
1012 }
1013
1014 // --------------------------------------------------------------------------------------------------------------------
1015 // kern.ipc.shm
1016
1017 int do_kern_ipc_shm(int update_every, usec_t dt) {
1018     (void)dt;
1019     static int mib_shmmni[3] = {0, 0, 0}, mib_shmsegs[3] = {0, 0, 0};
1020     struct ipc_shm {
1021         u_long shmmni;
1022         collected_number segs;
1023         collected_number segsize;
1024     } ipc_shm = {0, 0, 0};
1025
1026     if (unlikely(GETSYSCTL_SIMPLE("kern.ipc.shmmni", mib_shmmni, ipc_shm.shmmni))) {
1027         error("DISABLED: system.ipc_shared_mem_segs chart");
1028         error("DISABLED: system.ipc_shared_mem_size chart");
1029         error("DISABLED: kern.ipc.shmmodule");
1030         return 1;
1031     } else {
1032         static struct shmid_kernel *ipc_shm_data = NULL;
1033         static u_long old_shmmni = 0;
1034
1035         if (unlikely(ipc_shm.shmmni != old_shmmni)) {
1036             ipc_shm_data = reallocz(ipc_shm_data, sizeof(struct shmid_kernel) * ipc_shm.shmmni);
1037             old_shmmni = ipc_shm.shmmni;
1038         }
1039         if (unlikely(
1040                 GETSYSCTL_WSIZE("kern.ipc.shmsegs", mib_shmsegs, ipc_shm_data, sizeof(struct shmid_kernel) * ipc_shm.shmmni))) {
1041             error("DISABLED: system.ipc_shared_mem_segs chart");
1042             error("DISABLED: system.ipc_shared_mem_size chart");
1043             error("DISABLED: kern.ipc.shmmodule");
1044             return 1;
1045         } else {
1046             unsigned long i;
1047
1048             for (i = 0; i < ipc_shm.shmmni; i++) {
1049                 if (unlikely(ipc_shm_data[i].u.shm_perm.mode & 0x0800)) {
1050                     ipc_shm.segs += 1;
1051                     ipc_shm.segsize += ipc_shm_data[i].u.shm_segsz;
1052                 }
1053             }
1054
1055             // --------------------------------------------------------------------
1056
1057             static RRDSET *st_segs = NULL, *st_size = NULL;
1058             static RRDDIM *rd_segments = NULL, *rd_allocated = NULL;
1059
1060             if (unlikely(!st_segs)) {
1061                 st_segs = rrdset_create_localhost("system",
1062                                              "ipc_shared_mem_segs",
1063                                              NULL,
1064                                              "ipc shared memory",
1065                                              NULL,
1066                                              "IPC Shared Memory Segments",
1067                                              "segments",
1068                                              1000,
1069                                              update_every,
1070                                              RRDSET_TYPE_AREA
1071                 );
1072
1073                 rd_segments = rrddim_add(st_segs, "segments", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1074             }
1075             else rrdset_next(st_segs);
1076
1077             rrddim_set_by_pointer(st_segs, rd_segments, ipc_shm.segs);
1078             rrdset_done(st_segs);
1079
1080             // --------------------------------------------------------------------
1081
1082             if (unlikely(!st_size)) {
1083                 st_size = rrdset_create_localhost("system",
1084                                              "ipc_shared_mem_size",
1085                                              NULL,
1086                                              "ipc shared memory",
1087                                              NULL,
1088                                              "IPC Shared Memory Segments Size",
1089                                              "kilobytes",
1090                                              1000,
1091                                              update_every,
1092                                              RRDSET_TYPE_AREA
1093                 );
1094
1095                 rd_allocated = rrddim_add(st_size, "allocated", NULL, 1, KILO_FACTOR, RRD_ALGORITHM_ABSOLUTE);
1096             }
1097             else rrdset_next(st_size);
1098
1099             rrddim_set_by_pointer(st_size, rd_allocated, ipc_shm.segsize);
1100             rrdset_done(st_size);
1101         }
1102     }
1103
1104     return 0;
1105 }
1106
1107 // --------------------------------------------------------------------------------------------------------------------
1108 // kern.ipc.msq
1109
1110 int do_kern_ipc_msq(int update_every, usec_t dt) {
1111     (void)dt;
1112     static int mib_msgmni[3] = {0, 0, 0}, mib_msqids[3] = {0, 0, 0};
1113     struct ipc_msq {
1114         int msgmni;
1115         collected_number queues;
1116         collected_number messages;
1117         collected_number usedsize;
1118         collected_number allocsize;
1119     } ipc_msq = {0, 0, 0, 0, 0};
1120
1121     if (unlikely(GETSYSCTL_SIMPLE("kern.ipc.msgmni", mib_msgmni, ipc_msq.msgmni))) {
1122         error("DISABLED: system.ipc_msq_queues chart");
1123         error("DISABLED: system.ipc_msq_messages chart");
1124         error("DISABLED: system.ipc_msq_size chart");
1125         error("DISABLED: kern.ipc.msg module");
1126         return 1;
1127     } else {
1128         static struct msqid_kernel *ipc_msq_data = NULL;
1129         static int old_msgmni = 0;
1130
1131         if (unlikely(ipc_msq.msgmni != old_msgmni)) {
1132             ipc_msq_data = reallocz(ipc_msq_data, sizeof(struct msqid_kernel) * ipc_msq.msgmni);
1133             old_msgmni = ipc_msq.msgmni;
1134         }
1135         if (unlikely(
1136                 GETSYSCTL_WSIZE("kern.ipc.msqids", mib_msqids, ipc_msq_data, sizeof(struct msqid_kernel) * ipc_msq.msgmni))) {
1137             error("DISABLED: system.ipc_msq_queues chart");
1138             error("DISABLED: system.ipc_msq_messages chart");
1139             error("DISABLED: system.ipc_msq_size chart");
1140             error("DISABLED: kern.ipc.msg module");
1141             return 1;
1142         } else {
1143             int i;
1144
1145             for (i = 0; i < ipc_msq.msgmni; i++) {
1146                 if (unlikely(ipc_msq_data[i].u.msg_qbytes != 0)) {
1147                     ipc_msq.queues += 1;
1148                     ipc_msq.messages += ipc_msq_data[i].u.msg_qnum;
1149                     ipc_msq.usedsize += ipc_msq_data[i].u.msg_cbytes;
1150                     ipc_msq.allocsize += ipc_msq_data[i].u.msg_qbytes;
1151                 }
1152             }
1153
1154             // --------------------------------------------------------------------
1155
1156             static RRDSET *st_queues = NULL, *st_messages = NULL, *st_size = NULL;
1157             static RRDDIM *rd_queues = NULL, *rd_messages = NULL, *rd_allocated = NULL, *rd_used = NULL;
1158
1159             if (unlikely(!st_queues)) {
1160                 st_queues = rrdset_create_localhost("system",
1161                                                     "ipc_msq_queues",
1162                                                     NULL,
1163                                                     "ipc message queues",
1164                                                     NULL,
1165                                                     "Number of IPC Message Queues",
1166                                                     "queues",
1167                                                     990,
1168                                                     update_every,
1169                                                     RRDSET_TYPE_AREA
1170                 );
1171
1172                 rd_queues = rrddim_add(st_queues, "queues", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1173             }
1174             else rrdset_next(st_queues);
1175
1176             rrddim_set_by_pointer(st_queues, rd_queues, ipc_msq.queues);
1177             rrdset_done(st_queues);
1178
1179             // --------------------------------------------------------------------
1180
1181             if (unlikely(!st_messages)) {
1182                 st_messages = rrdset_create_localhost("system",
1183                                                       "ipc_msq_messages",
1184                                                       NULL,
1185                                                       "ipc message queues",
1186                                                       NULL,
1187                                                       "Number of Messages in IPC Message Queues",
1188                                                       "messages",
1189                                                       1000,
1190                                                       update_every,
1191                                                       RRDSET_TYPE_AREA
1192                 );
1193
1194                 rd_messages = rrddim_add(st_messages, "messages", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1195             }
1196             else rrdset_next(st_messages);
1197
1198             rrddim_set_by_pointer(st_messages, rd_messages, ipc_msq.messages);
1199             rrdset_done(st_messages);
1200
1201             // --------------------------------------------------------------------
1202
1203             if (unlikely(!st_size)) {
1204                 st_size = rrdset_create_localhost("system",
1205                                              "ipc_msq_size",
1206                                              NULL,
1207                                              "ipc message queues",
1208                                              NULL,
1209                                              "Size of IPC Message Queues",
1210                                              "bytes",
1211                                              1100,
1212                                              update_every,
1213                                              RRDSET_TYPE_LINE
1214                 );
1215
1216                 rd_allocated = rrddim_add(st_size, "allocated", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1217                 rd_used = rrddim_add(st_size, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1218             }
1219             else rrdset_next(st_size);
1220
1221             rrddim_set_by_pointer(st_size, rd_allocated, ipc_msq.allocsize);
1222             rrddim_set_by_pointer(st_size, rd_used, ipc_msq.usedsize);
1223             rrdset_done(st_size);
1224         }
1225     }
1226
1227     return 0;
1228 }
1229
1230 // --------------------------------------------------------------------------------------------------------------------
1231 // uptime
1232
1233 int do_uptime(int update_every, usec_t dt) {
1234     (void)dt;
1235     struct timespec up_time;
1236
1237     clock_gettime(CLOCK_UPTIME, &up_time);
1238
1239     // --------------------------------------------------------------------
1240
1241     static RRDSET *st = NULL;
1242     static RRDDIM *rd = NULL;
1243
1244     if(unlikely(!st)) {
1245         st = rrdset_create_localhost("system",
1246                                      "uptime",
1247                                      NULL,
1248                                      "uptime",
1249                                      NULL,
1250                                      "System Uptime",
1251                                      "seconds",
1252                                      1000,
1253                                      update_every,
1254                                      RRDSET_TYPE_LINE
1255         );
1256
1257         rd = rrddim_add(st, "uptime", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1258     }
1259     else rrdset_next(st);
1260
1261     rrddim_set_by_pointer(st, rd, up_time.tv_sec);
1262     rrdset_done(st);
1263
1264     return 0;
1265 }
1266
1267 // --------------------------------------------------------------------------------------------------------------------
1268 // net.isr
1269
1270 int do_net_isr(int update_every, usec_t dt) {
1271     (void)dt;
1272     static int do_netisr = -1, do_netisr_per_core = -1;
1273
1274     if (unlikely(do_netisr == -1)) {
1275         do_netisr =          config_get_boolean("plugin:freebsd:net.isr", "netisr",          1);
1276         do_netisr_per_core = config_get_boolean("plugin:freebsd:net.isr", "netisr per core", 1);
1277     }
1278
1279     static int mib_workstream[3] = {0, 0, 0}, mib_work[3] = {0, 0, 0};
1280     int common_error = 0;
1281     size_t netisr_workstream_size = sizeof(mib_workstream), netisr_work_size = sizeof(mib_work);
1282     unsigned long num_netisr_workstreams = 0, num_netisr_works = 0;
1283     static struct sysctl_netisr_workstream *netisr_workstream = NULL;
1284     static struct sysctl_netisr_work *netisr_work = NULL;
1285     static struct netisr_stats {
1286         collected_number dispatched;
1287         collected_number hybrid_dispatched;
1288         collected_number qdrops;
1289         collected_number queued;
1290     } *netisr_stats = NULL;
1291
1292     if (likely(do_netisr || do_netisr_per_core)) {
1293         if (unlikely(GETSYSCTL_SIZE("net.isr.workstream", mib_workstream, netisr_workstream_size))) {
1294             common_error = 1;
1295         } else if (unlikely(GETSYSCTL_SIZE("net.isr.work", mib_work, netisr_work_size))) {
1296             common_error = 1;
1297         } else {
1298             static size_t old_netisr_workstream_size = 0;
1299
1300             num_netisr_workstreams = netisr_workstream_size / sizeof(struct sysctl_netisr_workstream);
1301             if (unlikely(netisr_workstream_size != old_netisr_workstream_size)) {
1302                 netisr_workstream = reallocz(netisr_workstream,
1303                                              num_netisr_workstreams * sizeof(struct sysctl_netisr_workstream));
1304                 old_netisr_workstream_size = netisr_workstream_size;
1305             }
1306             if (unlikely(GETSYSCTL_WSIZE("net.isr.workstream", mib_workstream, netisr_workstream,
1307                                            num_netisr_workstreams * sizeof(struct sysctl_netisr_workstream)))){
1308                 common_error = 1;
1309             } else {
1310                 static size_t old_netisr_work_size = 0;
1311
1312                 num_netisr_works = netisr_work_size / sizeof(struct sysctl_netisr_work);
1313                 if (unlikely(netisr_work_size != old_netisr_work_size)) {
1314                     netisr_work = reallocz(netisr_work, num_netisr_works * sizeof(struct sysctl_netisr_work));
1315                     old_netisr_work_size = netisr_work_size;
1316                 }
1317                 if (unlikely(GETSYSCTL_WSIZE("net.isr.work", mib_work, netisr_work,
1318                                                num_netisr_works * sizeof(struct sysctl_netisr_work)))){
1319                     common_error = 1;
1320                 }
1321             }
1322         }
1323         if (unlikely(common_error)) {
1324             do_netisr = 0;
1325             error("DISABLED: system.softnet_stat chart");
1326             do_netisr_per_core = 0;
1327             error("DISABLED: system.cpuX_softnet_stat chart");
1328             common_error = 0;
1329             error("DISABLED: net.isr module");
1330             return 1;
1331         } else {
1332             unsigned long i, n;
1333             int j;
1334             static int old_number_of_cpus = 0;
1335
1336             if (unlikely(number_of_cpus != old_number_of_cpus)) {
1337                 netisr_stats = reallocz(netisr_stats, (number_of_cpus + 1) * sizeof(struct netisr_stats));
1338                 old_number_of_cpus = number_of_cpus;
1339             }
1340             memset(netisr_stats, 0, (number_of_cpus + 1) * sizeof(struct netisr_stats));
1341             for (i = 0; i < num_netisr_workstreams; i++) {
1342                 for (n = 0; n < num_netisr_works; n++) {
1343                     if (netisr_workstream[i].snws_wsid == netisr_work[n].snw_wsid) {
1344                         netisr_stats[netisr_workstream[i].snws_cpu].dispatched += netisr_work[n].snw_dispatched;
1345                         netisr_stats[netisr_workstream[i].snws_cpu].hybrid_dispatched += netisr_work[n].snw_hybrid_dispatched;
1346                         netisr_stats[netisr_workstream[i].snws_cpu].qdrops += netisr_work[n].snw_qdrops;
1347                         netisr_stats[netisr_workstream[i].snws_cpu].queued += netisr_work[n].snw_queued;
1348                     }
1349                 }
1350             }
1351             for (j = 0; j < number_of_cpus; j++) {
1352                 netisr_stats[number_of_cpus].dispatched += netisr_stats[j].dispatched;
1353                 netisr_stats[number_of_cpus].hybrid_dispatched += netisr_stats[j].hybrid_dispatched;
1354                 netisr_stats[number_of_cpus].qdrops += netisr_stats[j].qdrops;
1355                 netisr_stats[number_of_cpus].queued += netisr_stats[j].queued;
1356             }
1357         }
1358     } else {
1359         error("DISABLED: net.isr module");
1360         return 1;
1361     }
1362
1363     // --------------------------------------------------------------------
1364
1365     if (likely(do_netisr)) {
1366         static RRDSET *st = NULL;
1367         static RRDDIM *rd_dispatched = NULL, *rd_hybrid_dispatched = NULL, *rd_qdrops = NULL, *rd_queued = NULL;
1368
1369         if (unlikely(!st)) {
1370             st = rrdset_create_localhost("system",
1371                                          "softnet_stat",
1372                                          NULL,
1373                                          "softnet_stat",
1374                                          NULL,
1375                                          "System softnet_stat",
1376                                          "events/s",
1377                                          955,
1378                                          update_every,
1379                                          RRDSET_TYPE_LINE
1380             );
1381
1382             rd_dispatched        = rrddim_add(st, "dispatched",        NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1383             rd_hybrid_dispatched = rrddim_add(st, "hybrid_dispatched", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1384             rd_qdrops            = rrddim_add(st, "qdrops",            NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1385             rd_queued            = rrddim_add(st, "queued",            NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1386         }
1387         else rrdset_next(st);
1388
1389         rrddim_set_by_pointer(st, rd_dispatched,        netisr_stats[number_of_cpus].dispatched);
1390         rrddim_set_by_pointer(st, rd_hybrid_dispatched, netisr_stats[number_of_cpus].hybrid_dispatched);
1391         rrddim_set_by_pointer(st, rd_qdrops,            netisr_stats[number_of_cpus].qdrops);
1392         rrddim_set_by_pointer(st, rd_queued,            netisr_stats[number_of_cpus].queued);
1393         rrdset_done(st);
1394     }
1395
1396     // --------------------------------------------------------------------
1397
1398     if (likely(do_netisr_per_core)) {
1399         static struct softnet_chart {
1400             char netisr_cpuid[MAX_INT_DIGITS + 17];
1401             RRDSET *st;
1402             RRDDIM *rd_dispatched;
1403             RRDDIM *rd_hybrid_dispatched;
1404             RRDDIM *rd_qdrops;
1405             RRDDIM *rd_queued;
1406         } *all_softnet_charts = NULL;
1407         static int old_number_of_cpus = 0;
1408         int i;
1409
1410         if(unlikely(number_of_cpus > old_number_of_cpus)) {
1411             all_softnet_charts = reallocz(all_softnet_charts, sizeof(struct softnet_chart) * number_of_cpus);
1412             memset(&all_softnet_charts[old_number_of_cpus], 0, sizeof(struct softnet_chart) * (number_of_cpus - old_number_of_cpus));
1413             old_number_of_cpus = number_of_cpus;
1414         }
1415
1416         for (i = 0; i < number_of_cpus ;i++) {
1417             snprintfz(all_softnet_charts[i].netisr_cpuid, MAX_INT_DIGITS + 17, "cpu%d_softnet_stat", i);
1418
1419             if (unlikely(!all_softnet_charts[i].st)) {
1420                 all_softnet_charts[i].st = rrdset_create_localhost("cpu",
1421                                                                    all_softnet_charts[i].netisr_cpuid,
1422                                                                    NULL,
1423                                                                    "softnet_stat",
1424                                                                    NULL,
1425                                                                    "Per CPU netisr statistics",
1426                                                                    "events/s",
1427                                                                    1101 + i,
1428                                                                    update_every,
1429                                                                    RRDSET_TYPE_LINE
1430                 );
1431
1432                 all_softnet_charts[i].rd_dispatched        = rrddim_add(all_softnet_charts[i].st, "dispatched",
1433                                                                 NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1434                 all_softnet_charts[i].rd_hybrid_dispatched = rrddim_add(all_softnet_charts[i].st, "hybrid_dispatched",
1435                                                                 NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1436                 all_softnet_charts[i].rd_qdrops            = rrddim_add(all_softnet_charts[i].st, "qdrops",
1437                                                                 NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1438                 all_softnet_charts[i].rd_queued            = rrddim_add(all_softnet_charts[i].st, "queued",
1439                                                                 NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1440             }
1441             else rrdset_next(all_softnet_charts[i].st);
1442
1443             rrddim_set_by_pointer(all_softnet_charts[i].st, all_softnet_charts[i].rd_dispatched,
1444                                   netisr_stats[i].dispatched);
1445             rrddim_set_by_pointer(all_softnet_charts[i].st, all_softnet_charts[i].rd_hybrid_dispatched,
1446                                   netisr_stats[i].hybrid_dispatched);
1447             rrddim_set_by_pointer(all_softnet_charts[i].st, all_softnet_charts[i].rd_qdrops,
1448                                   netisr_stats[i].qdrops);
1449             rrddim_set_by_pointer(all_softnet_charts[i].st, all_softnet_charts[i].rd_queued,
1450                                   netisr_stats[i].queued);
1451             rrdset_done(all_softnet_charts[i].st);
1452         }
1453     }
1454
1455     return 0;
1456 }
1457
1458 // --------------------------------------------------------------------------------------------------------------------
1459 // net.inet.tcp.states
1460
1461 int do_net_inet_tcp_states(int update_every, usec_t dt) {
1462     (void)dt;
1463     static int mib[4] = {0, 0, 0, 0};
1464     uint64_t tcps_states[TCP_NSTATES];
1465
1466     // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
1467     if (unlikely(GETSYSCTL_SIMPLE("net.inet.tcp.states", mib, tcps_states))) {
1468         error("DISABLED: ipv4.tcpsock chart");
1469         error("DISABLED: net.inet.tcp.states module");
1470         return 1;
1471     } else {
1472
1473         // --------------------------------------------------------------------
1474
1475         static RRDSET *st = NULL;
1476         static RRDDIM *rd = NULL;
1477
1478         if (unlikely(!st)) {
1479             st = rrdset_create_localhost("ipv4",
1480                                          "tcpsock",
1481                                          NULL,
1482                                          "tcp",
1483                                          NULL,
1484                                          "IPv4 TCP Connections",
1485                                          "active connections",
1486                                          2500,
1487                                          update_every,
1488                                          RRDSET_TYPE_LINE
1489             );
1490
1491             rd = rrddim_add(st, "CurrEstab", "connections", 1, 1, RRD_ALGORITHM_ABSOLUTE);
1492         } else
1493             rrdset_next(st);
1494
1495         rrddim_set_by_pointer(st, rd, tcps_states[TCPS_ESTABLISHED]);
1496         rrdset_done(st);
1497     }
1498
1499     return 0;
1500 }
1501
1502 // --------------------------------------------------------------------------------------------------------------------
1503 // net.inet.tcp.stats
1504
1505 int do_net_inet_tcp_stats(int update_every, usec_t dt) {
1506     (void)dt;
1507     static int do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1, do_tcpext_connaborts = -1, do_tcpext_ofo = -1, do_tcpext_syncookies = -1, do_ecn = -1;
1508
1509     if (unlikely(do_tcp_packets == -1)) {
1510         do_tcp_packets       = config_get_boolean("plugin:freebsd:net.inet.tcp.stats", "ipv4 TCP packets",          1);
1511         do_tcp_errors        = config_get_boolean("plugin:freebsd:net.inet.tcp.stats", "ipv4 TCP errors",           1);
1512         do_tcp_handshake     = config_get_boolean("plugin:freebsd:net.inet.tcp.stats", "ipv4 TCP handshake issues", 1);
1513         do_tcpext_connaborts = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "TCP connection aborts",
1514                                                            CONFIG_BOOLEAN_AUTO);
1515         do_tcpext_ofo        = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "TCP out-of-order queue",
1516                                                            CONFIG_BOOLEAN_AUTO);
1517         do_tcpext_syncookies = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "TCP SYN cookies",
1518                                                            CONFIG_BOOLEAN_AUTO);
1519         do_ecn               = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "ECN packets",
1520                                                            CONFIG_BOOLEAN_AUTO);
1521     }
1522
1523     // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
1524     if (likely(do_tcp_packets || do_tcp_errors || do_tcp_handshake || do_tcpext_connaborts || do_tcpext_ofo || do_tcpext_syncookies || do_ecn)) {
1525         static int mib[4] = {0, 0, 0, 0};
1526         struct tcpstat tcpstat;
1527
1528         if (unlikely(GETSYSCTL_SIMPLE("net.inet.tcp.stats", mib, tcpstat))) {
1529             do_tcp_packets = 0;
1530             error("DISABLED: ipv4.tcppackets chart");
1531             do_tcp_errors = 0;
1532             error("DISABLED: ipv4.tcperrors  chart");
1533             do_tcp_handshake = 0;
1534             error("DISABLED: ipv4.tcphandshake  chart");
1535             do_tcpext_connaborts = 0;
1536             error("DISABLED: ipv4.tcpconnaborts  chart");
1537             do_tcpext_ofo = 0;
1538             error("DISABLED: ipv4.tcpofo chart");
1539             do_tcpext_syncookies = 0;
1540             error("DISABLED: ipv4.tcpsyncookies chart");
1541             do_ecn = 0;
1542             error("DISABLED: ipv4.ecnpkts chart");
1543             error("DISABLED: net.inet.tcp.stats module");
1544             return 1;
1545         } else {
1546
1547             // --------------------------------------------------------------------
1548
1549             if (likely(do_tcp_packets)) {
1550                 static RRDSET *st = NULL;
1551                 static RRDDIM *rd_in_segs = NULL, *rd_out_segs = NULL;
1552
1553                 if (unlikely(!st)) {
1554                     st = rrdset_create_localhost("ipv4",
1555                                                  "tcppackets",
1556                                                  NULL,
1557                                                  "tcp",
1558                                                  NULL,
1559                                                  "IPv4 TCP Packets",
1560                                                  "packets/s",
1561                                                  2600,
1562                                                  update_every,
1563                                                  RRDSET_TYPE_LINE
1564                     );
1565
1566                     rd_in_segs  = rrddim_add(st, "InSegs",  "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
1567                     rd_out_segs = rrddim_add(st, "OutSegs", "sent",    -1, 1, RRD_ALGORITHM_INCREMENTAL);
1568                 } else
1569                     rrdset_next(st);
1570
1571                 rrddim_set_by_pointer(st, rd_in_segs,  tcpstat.tcps_rcvtotal);
1572                 rrddim_set_by_pointer(st, rd_out_segs, tcpstat.tcps_sndtotal);
1573                 rrdset_done(st);
1574             }
1575
1576             // --------------------------------------------------------------------
1577
1578             if (likely(do_tcp_errors)) {
1579                 static RRDSET *st = NULL;
1580                 static RRDDIM *rd_in_errs = NULL, *rd_in_csum_errs = NULL, *rd_retrans_segs = NULL;
1581
1582                 if (unlikely(!st)) {
1583                     st = rrdset_create_localhost("ipv4",
1584                                                  "tcperrors",
1585                                                  NULL,
1586                                                  "tcp",
1587                                                  NULL,
1588                                                  "IPv4 TCP Errors",
1589                                                  "packets/s",
1590                                                  2700,
1591                                                  update_every,
1592                                                  RRDSET_TYPE_LINE
1593                     );
1594
1595                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
1596
1597                     rd_in_errs      = rrddim_add(st, "InErrs",       NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1598                     rd_in_csum_errs = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1599                     rd_retrans_segs = rrddim_add(st, "RetransSegs",  NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1600                 } else
1601                     rrdset_next(st);
1602
1603 #if __FreeBSD__ >= 11
1604                 rrddim_set_by_pointer(st, rd_in_errs,      tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvreassfull +
1605                                                            tcpstat.tcps_rcvshort);
1606 #else
1607                 rrddim_set_by_pointer(st, rd_in_errs,      tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvshort);
1608 #endif
1609                 rrddim_set_by_pointer(st, rd_in_csum_errs, tcpstat.tcps_rcvbadsum);
1610                 rrddim_set_by_pointer(st, rd_retrans_segs, tcpstat.tcps_sndrexmitpack);
1611                 rrdset_done(st);
1612             }
1613
1614             // --------------------------------------------------------------------
1615
1616             if (likely(do_tcp_handshake)) {
1617                 static RRDSET *st = NULL;
1618                 static RRDDIM *rd_estab_resets = NULL, *rd_active_opens = NULL, *rd_passive_opens = NULL,
1619                               *rd_attempt_fails = NULL;
1620
1621                 if (unlikely(!st)) {
1622                     st = rrdset_create_localhost("ipv4",
1623                                                  "tcphandshake",
1624                                                  NULL,
1625                                                  "tcp",
1626                                                  NULL,
1627                                                  "IPv4 TCP Handshake Issues",
1628                                                  "events/s",
1629                                                  2900,
1630                                                  update_every,
1631                                                  RRDSET_TYPE_LINE
1632                     );
1633
1634                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
1635
1636                     rd_estab_resets  = rrddim_add(st, "EstabResets",  NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1637                     rd_active_opens  = rrddim_add(st, "ActiveOpens",  NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1638                     rd_passive_opens = rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1639                     rd_attempt_fails = rrddim_add(st, "AttemptFails", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1640                 } else
1641                     rrdset_next(st);
1642
1643                 rrddim_set_by_pointer(st, rd_estab_resets,  tcpstat.tcps_drops);
1644                 rrddim_set_by_pointer(st, rd_active_opens,  tcpstat.tcps_connattempt);
1645                 rrddim_set_by_pointer(st, rd_passive_opens, tcpstat.tcps_accepts);
1646                 rrddim_set_by_pointer(st, rd_attempt_fails, tcpstat.tcps_conndrops);
1647                 rrdset_done(st);
1648             }
1649
1650             // --------------------------------------------------------------------
1651
1652             if (do_tcpext_connaborts == CONFIG_BOOLEAN_YES || (do_tcpext_connaborts == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_rcvpackafterwin || tcpstat.tcps_rcvafterclose || tcpstat.tcps_rcvmemdrop || tcpstat.tcps_persistdrop || tcpstat.tcps_finwait2_drops))) {
1653                 do_tcpext_connaborts = CONFIG_BOOLEAN_YES;
1654
1655                 static RRDSET *st = NULL;
1656                 static RRDDIM *rd_on_data = NULL, *rd_on_close = NULL, *rd_on_memory = NULL,
1657                               *rd_on_timeout = NULL, *rd_on_linger = NULL;
1658
1659                 if (unlikely(!st)) {
1660                     st = rrdset_create_localhost("ipv4",
1661                                                  "tcpconnaborts",
1662                                                  NULL,
1663                                                  "tcp",
1664                                                  NULL,
1665                                                  "TCP Connection Aborts",
1666                                                  "connections/s",
1667                                                  3010,
1668                                                  update_every,
1669                                                  RRDSET_TYPE_LINE
1670                     );
1671
1672                     rd_on_data    = rrddim_add(st, "TCPAbortOnData",    "baddata",     1, 1, RRD_ALGORITHM_INCREMENTAL);
1673                     rd_on_close   = rrddim_add(st, "TCPAbortOnClose",   "userclosed",  1, 1, RRD_ALGORITHM_INCREMENTAL);
1674                     rd_on_memory  = rrddim_add(st, "TCPAbortOnMemory",  "nomemory",    1, 1, RRD_ALGORITHM_INCREMENTAL);
1675                     rd_on_timeout = rrddim_add(st, "TCPAbortOnTimeout", "timeout",     1, 1, RRD_ALGORITHM_INCREMENTAL);
1676                     rd_on_linger  = rrddim_add(st, "TCPAbortOnLinger",  "linger",      1, 1, RRD_ALGORITHM_INCREMENTAL);
1677                 }
1678                 else rrdset_next(st);
1679
1680                 rrddim_set_by_pointer(st, rd_on_data,    tcpstat.tcps_rcvpackafterwin);
1681                 rrddim_set_by_pointer(st, rd_on_close,   tcpstat.tcps_rcvafterclose);
1682                 rrddim_set_by_pointer(st, rd_on_memory,  tcpstat.tcps_rcvmemdrop);
1683                 rrddim_set_by_pointer(st, rd_on_timeout, tcpstat.tcps_persistdrop);
1684                 rrddim_set_by_pointer(st, rd_on_linger,  tcpstat.tcps_finwait2_drops);
1685                 rrdset_done(st);
1686             }
1687
1688             // --------------------------------------------------------------------
1689
1690             if (do_tcpext_ofo == CONFIG_BOOLEAN_YES || (do_tcpext_ofo == CONFIG_BOOLEAN_AUTO && tcpstat.tcps_rcvoopack)) {
1691                 do_tcpext_ofo = CONFIG_BOOLEAN_YES;
1692
1693                 static RRDSET *st = NULL;
1694                 static RRDDIM *rd_ofo_queue = NULL;
1695
1696                 if (unlikely(!st)) {
1697                     st = rrdset_create_localhost("ipv4",
1698                                                  "tcpofo",
1699                                                  NULL,
1700                                                  "tcp",
1701                                                  NULL,
1702                                                  "TCP Out-Of-Order Queue",
1703                                                  "packets/s",
1704                                                  3050,
1705                                                  update_every,
1706                                                  RRDSET_TYPE_LINE
1707                     );
1708
1709                     rd_ofo_queue = rrddim_add(st, "TCPOFOQueue", "inqueue",  1, 1, RRD_ALGORITHM_INCREMENTAL);
1710                 }
1711                 else rrdset_next(st);
1712
1713                 rrddim_set_by_pointer(st, rd_ofo_queue,   tcpstat.tcps_rcvoopack);
1714                 rrdset_done(st);
1715             }
1716
1717             // --------------------------------------------------------------------
1718
1719             if (do_tcpext_syncookies == CONFIG_BOOLEAN_YES || (do_tcpext_syncookies == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_sc_sendcookie || tcpstat.tcps_sc_recvcookie || tcpstat.tcps_sc_zonefail))) {
1720                 do_tcpext_syncookies = CONFIG_BOOLEAN_YES;
1721
1722                 static RRDSET *st = NULL;
1723                 static RRDDIM *rd_recv = NULL, *rd_send = NULL, *rd_failed = NULL;
1724
1725                 if (unlikely(!st)) {
1726                     st = rrdset_create_localhost("ipv4",
1727                                                  "tcpsyncookies",
1728                                                  NULL,
1729                                                  "tcp",
1730                                                  NULL,
1731                                                  "TCP SYN Cookies",
1732                                                  "packets/s",
1733                                                  3100,
1734                                                  update_every,
1735                                                  RRDSET_TYPE_LINE
1736                     );
1737
1738                     rd_recv   = rrddim_add(st, "SyncookiesRecv",   "received",  1, 1, RRD_ALGORITHM_INCREMENTAL);
1739                     rd_send   = rrddim_add(st, "SyncookiesSent",   "sent",     -1, 1, RRD_ALGORITHM_INCREMENTAL);
1740                     rd_failed = rrddim_add(st, "SyncookiesFailed", "failed",   -1, 1, RRD_ALGORITHM_INCREMENTAL);
1741                 }
1742                 else rrdset_next(st);
1743
1744                 rrddim_set_by_pointer(st, rd_recv,   tcpstat.tcps_sc_recvcookie);
1745                 rrddim_set_by_pointer(st, rd_send,   tcpstat.tcps_sc_sendcookie);
1746                 rrddim_set_by_pointer(st, rd_failed, tcpstat.tcps_sc_zonefail);
1747                 rrdset_done(st);
1748             }
1749
1750             // --------------------------------------------------------------------
1751
1752             if (do_ecn == CONFIG_BOOLEAN_YES || (do_ecn == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_ecn_ce || tcpstat.tcps_ecn_ect0 || tcpstat.tcps_ecn_ect1))) {
1753                 do_ecn = CONFIG_BOOLEAN_YES;
1754
1755                 static RRDSET *st = NULL;
1756                 static RRDDIM *rd_ce = NULL, *rd_no_ect = NULL, *rd_ect0 = NULL, *rd_ect1 = NULL;
1757
1758                 if (unlikely(!st)) {
1759                     st = rrdset_create_localhost("ipv4",
1760                                                  "ecnpkts",
1761                                                  NULL,
1762                                                  "ecn",
1763                                                  NULL,
1764                                                  "IPv4 ECN Statistics",
1765                                                  "packets/s",
1766                                                  8700,
1767                                                  update_every,
1768                                                  RRDSET_TYPE_LINE
1769                     );
1770
1771                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
1772
1773                     rd_ce     = rrddim_add(st, "InCEPkts", "CEP", 1, 1, RRD_ALGORITHM_INCREMENTAL);
1774                     rd_no_ect = rrddim_add(st, "InNoECTPkts", "NoECTP", -1, 1, RRD_ALGORITHM_INCREMENTAL);
1775                     rd_ect0   = rrddim_add(st, "InECT0Pkts", "ECTP0", 1, 1, RRD_ALGORITHM_INCREMENTAL);
1776                     rd_ect1   = rrddim_add(st, "InECT1Pkts", "ECTP1", 1, 1, RRD_ALGORITHM_INCREMENTAL);
1777                 }
1778                 else rrdset_next(st);
1779
1780                 rrddim_set_by_pointer(st, rd_ce,     tcpstat.tcps_ecn_ce);
1781                 rrddim_set_by_pointer(st, rd_no_ect, tcpstat.tcps_ecn_ce - (tcpstat.tcps_ecn_ect0 +
1782                                                                             tcpstat.tcps_ecn_ect1));
1783                 rrddim_set_by_pointer(st, rd_ect0,   tcpstat.tcps_ecn_ect0);
1784                 rrddim_set_by_pointer(st, rd_ect1,   tcpstat.tcps_ecn_ect1);
1785                 rrdset_done(st);
1786             }
1787
1788         }
1789     } else {
1790         error("DISABLED: net.inet.tcp.stats module");
1791         return 1;
1792     }
1793
1794     return 0;
1795 }
1796
1797 // --------------------------------------------------------------------------------------------------------------------
1798 // net.inet.udp.stats
1799
1800 int do_net_inet_udp_stats(int update_every, usec_t dt) {
1801     (void)dt;
1802     static int do_udp_packets = -1, do_udp_errors = -1;
1803
1804     if (unlikely(do_udp_packets == -1)) {
1805         do_udp_packets = config_get_boolean("plugin:freebsd:net.inet.udp.stats", "ipv4 UDP packets", 1);
1806         do_udp_errors  = config_get_boolean("plugin:freebsd:net.inet.udp.stats", "ipv4 UDP errors", 1);
1807     }
1808
1809     // see http://net-snmp.sourceforge.net/docs/mibs/udp.html
1810     if (likely(do_udp_packets || do_udp_errors)) {
1811         static int mib[4] = {0, 0, 0, 0};
1812         struct udpstat udpstat;
1813
1814         if (unlikely(GETSYSCTL_SIMPLE("net.inet.udp.stats", mib, udpstat))) {
1815             do_udp_packets = 0;
1816             error("DISABLED: ipv4.udppackets chart");
1817             do_udp_errors = 0;
1818             error("DISABLED: ipv4.udperrors chart");
1819             error("DISABLED: net.inet.udp.stats module");
1820             return 1;
1821         } else {
1822
1823             // --------------------------------------------------------------------
1824
1825             if (likely(do_udp_packets)) {
1826                 static RRDSET *st = NULL;
1827                 static RRDDIM *rd_in = NULL, *rd_out = NULL;
1828
1829                 if (unlikely(!st)) {
1830                     st = rrdset_create_localhost("ipv4",
1831                                                  "udppackets",
1832                                                  NULL,
1833                                                  "udp",
1834                                                  NULL,
1835                                                  "IPv4 UDP Packets",
1836                                                  "packets/s",
1837                                                  2601,
1838                                                  update_every,
1839                                                  RRDSET_TYPE_LINE
1840                     );
1841
1842                     rd_in  = rrddim_add(st, "InDatagrams",  "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
1843                     rd_out = rrddim_add(st, "OutDatagrams", "sent",    -1, 1, RRD_ALGORITHM_INCREMENTAL);
1844                 } else
1845                     rrdset_next(st);
1846
1847                 rrddim_set_by_pointer(st, rd_in,  udpstat.udps_ipackets);
1848                 rrddim_set_by_pointer(st, rd_out, udpstat.udps_opackets);
1849                 rrdset_done(st);
1850             }
1851
1852             // --------------------------------------------------------------------
1853
1854             if (likely(do_udp_errors)) {
1855                 static RRDSET *st = NULL;
1856                 static RRDDIM *rd_in_errors = NULL, *rd_no_ports = NULL, *rd_recv_buf_errors = NULL,
1857                               *rd_in_csum_errors = NULL, *rd_ignored_multi = NULL;
1858
1859                 if (unlikely(!st)) {
1860                     st = rrdset_create_localhost("ipv4",
1861                                                  "udperrors",
1862                                                  NULL,
1863                                                  "udp",
1864                                                  NULL,
1865                                                  "IPv4 UDP Errors",
1866                                                  "events/s",
1867                                                  2701,
1868                                                  update_every,
1869                                                  RRDSET_TYPE_LINE
1870                     );
1871
1872                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
1873
1874                     rd_in_errors       = rrddim_add(st, "InErrors",     NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1875                     rd_no_ports        = rrddim_add(st, "NoPorts",      NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1876                     rd_recv_buf_errors = rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1877                     rd_in_csum_errors  = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1878                     rd_ignored_multi   = rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1879                 } else
1880                     rrdset_next(st);
1881
1882                 rrddim_set_by_pointer(st, rd_in_errors,       udpstat.udps_hdrops + udpstat.udps_badlen);
1883                 rrddim_set_by_pointer(st, rd_no_ports,        udpstat.udps_noport);
1884                 rrddim_set_by_pointer(st, rd_recv_buf_errors, udpstat.udps_fullsock);
1885                 rrddim_set_by_pointer(st, rd_in_csum_errors,  udpstat.udps_badsum + udpstat.udps_nosum);
1886                 rrddim_set_by_pointer(st, rd_ignored_multi,   udpstat.udps_filtermcast);
1887                 rrdset_done(st);
1888             }
1889         }
1890     } else {
1891         error("DISABLED: net.inet.udp.stats module");
1892         return 1;
1893     }
1894
1895     return 0;
1896 }
1897
1898 // --------------------------------------------------------------------------------------------------------------------
1899 // net.inet.icmp.stats
1900
1901 int do_net_inet_icmp_stats(int update_every, usec_t dt) {
1902     (void)dt;
1903     static int do_icmp_packets = -1, do_icmp_errors = -1, do_icmpmsg = -1;
1904
1905     if (unlikely(do_icmp_packets == -1)) {
1906         do_icmp_packets = config_get_boolean("plugin:freebsd:net.inet.icmp.stats", "ipv4 ICMP packets",  1);
1907         do_icmp_errors  = config_get_boolean("plugin:freebsd:net.inet.icmp.stats", "ipv4 ICMP errors",   1);
1908         do_icmpmsg      = config_get_boolean("plugin:freebsd:net.inet.icmp.stats", "ipv4 ICMP messages", 1);
1909     }
1910
1911     if (likely(do_icmp_packets || do_icmp_errors || do_icmpmsg)) {
1912         static int mib[4] = {0, 0, 0, 0};
1913         struct icmpstat icmpstat;
1914         int i;
1915         struct icmp_total {
1916             u_long  msgs_in;
1917             u_long  msgs_out;
1918         } icmp_total = {0, 0};
1919
1920         if (unlikely(GETSYSCTL_SIMPLE("net.inet.icmp.stats", mib, icmpstat))) {
1921             do_icmp_packets = 0;
1922             error("DISABLED: ipv4.icmp chart");
1923             do_icmp_errors = 0;
1924             error("DISABLED: ipv4.icmp_errors chart");
1925             do_icmpmsg = 0;
1926             error("DISABLED: ipv4.icmpmsg chart");
1927             error("DISABLED: net.inet.icmp.stats module");
1928             return 1;
1929         } else {
1930             for (i = 0; i <= ICMP_MAXTYPE; i++) {
1931                 icmp_total.msgs_in += icmpstat.icps_inhist[i];
1932                 icmp_total.msgs_out += icmpstat.icps_outhist[i];
1933             }
1934             icmp_total.msgs_in += icmpstat.icps_badcode + icmpstat.icps_badlen + icmpstat.icps_checksum + icmpstat.icps_tooshort;
1935
1936             // --------------------------------------------------------------------
1937
1938             if (likely(do_icmp_packets)) {
1939                 static RRDSET *st = NULL;
1940                 static RRDDIM *rd_in = NULL, *rd_out = NULL;
1941
1942                 if (unlikely(!st)) {
1943                     st = rrdset_create_localhost("ipv4",
1944                                                  "icmp",
1945                                                  NULL,
1946                                                  "icmp",
1947                                                  NULL,
1948                                                  "IPv4 ICMP Packets",
1949                                                  "packets/s",
1950                                                  2602,
1951                                                  update_every,
1952                                                  RRDSET_TYPE_LINE
1953                     );
1954
1955                     rd_in  = rrddim_add(st, "InMsgs",  "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
1956                     rd_out = rrddim_add(st, "OutMsgs", "sent",    -1, 1, RRD_ALGORITHM_INCREMENTAL);
1957                 } else
1958                     rrdset_next(st);
1959
1960                 rrddim_set_by_pointer(st, rd_in,  icmp_total.msgs_in);
1961                 rrddim_set_by_pointer(st, rd_out, icmp_total.msgs_out);
1962
1963                 rrdset_done(st);
1964             }
1965
1966             // --------------------------------------------------------------------
1967
1968             if (likely(do_icmp_errors)) {
1969                 static RRDSET *st = NULL;
1970                 static RRDDIM *rd_in = NULL, *rd_out = NULL, *rd_in_csum = NULL;
1971
1972                 if (unlikely(!st)) {
1973                     st = rrdset_create_localhost("ipv4", "icmp_errors", NULL, "icmp", NULL, "IPv4 ICMP Errors",
1974                                                  "packets/s",
1975                                                  2603, update_every, RRDSET_TYPE_LINE);
1976
1977                     rd_in      = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1978                     rd_out     = rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1979                     rd_in_csum = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1980                 } else
1981                     rrdset_next(st);
1982
1983                 rrddim_set_by_pointer(st, rd_in,      icmpstat.icps_badcode + icmpstat.icps_badlen +
1984                                                       icmpstat.icps_checksum + icmpstat.icps_tooshort);
1985                 rrddim_set_by_pointer(st, rd_out,     icmpstat.icps_error);
1986                 rrddim_set_by_pointer(st, rd_in_csum, icmpstat.icps_checksum);
1987
1988                 rrdset_done(st);
1989             }
1990
1991             // --------------------------------------------------------------------
1992
1993             if (likely(do_icmpmsg)) {
1994                 static RRDSET *st = NULL;
1995                 static RRDDIM *rd_in_reps = NULL, *rd_out_reps = NULL, *rd_in = NULL, *rd_out = NULL;
1996
1997                 if (unlikely(!st)) {
1998                     st = rrdset_create_localhost("ipv4", "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages",
1999                                                  "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
2000
2001                     rd_in_reps  = rrddim_add(st, "InEchoReps",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2002                     rd_out_reps = rrddim_add(st, "OutEchoReps", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2003                     rd_in       = rrddim_add(st, "InEchos",     NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2004                     rd_out      = rrddim_add(st, "OutEchos",    NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2005                 } else
2006                     rrdset_next(st);
2007
2008                 rrddim_set_by_pointer(st, rd_in_reps, icmpstat.icps_inhist[ICMP_ECHOREPLY]);
2009                 rrddim_set_by_pointer(st, rd_out_reps, icmpstat.icps_outhist[ICMP_ECHOREPLY]);
2010                 rrddim_set_by_pointer(st, rd_in, icmpstat.icps_inhist[ICMP_ECHO]);
2011                 rrddim_set_by_pointer(st, rd_out, icmpstat.icps_outhist[ICMP_ECHO]);
2012
2013                 rrdset_done(st);
2014             }
2015         }
2016     } else {
2017         error("DISABLED: net.inet.icmp.stats module");
2018         return 1;
2019     }
2020
2021     return 0;
2022 }
2023
2024 // --------------------------------------------------------------------------------------------------------------------
2025 // net.inet.ip.stats
2026
2027 int do_net_inet_ip_stats(int update_every, usec_t dt) {
2028     (void)dt;
2029     static int do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1;
2030
2031     if (unlikely(do_ip_packets == -1)) {
2032         do_ip_packets  = config_get_boolean("plugin:freebsd:net.inet.ip.stats", "ipv4 packets", 1);
2033         do_ip_fragsout = config_get_boolean("plugin:freebsd:net.inet.ip.stats", "ipv4 fragments sent", 1);
2034         do_ip_fragsin  = config_get_boolean("plugin:freebsd:net.inet.ip.stats", "ipv4 fragments assembly", 1);
2035         do_ip_errors   = config_get_boolean("plugin:freebsd:net.inet.ip.stats", "ipv4 errors", 1);
2036     }
2037
2038     // see also http://net-snmp.sourceforge.net/docs/mibs/ip.html
2039     if (likely(do_ip_packets || do_ip_fragsout || do_ip_fragsin || do_ip_errors)) {
2040         static int mib[4] = {0, 0, 0, 0};
2041         struct ipstat ipstat;
2042
2043         if (unlikely(GETSYSCTL_SIMPLE("net.inet.ip.stats", mib, ipstat))) {
2044             do_ip_packets = 0;
2045             error("DISABLED: ipv4.packets chart");
2046             do_ip_fragsout = 0;
2047             error("DISABLED: ipv4.fragsout chart");
2048             do_ip_fragsin = 0;
2049             error("DISABLED: ipv4.fragsin chart");
2050             do_ip_errors = 0;
2051             error("DISABLED: ipv4.errors chart");
2052             error("DISABLED: net.inet.ip.stats module");
2053             return 1;
2054         } else {
2055
2056             // --------------------------------------------------------------------
2057
2058             if (likely(do_ip_packets)) {
2059                 static RRDSET *st = NULL;
2060                 static RRDDIM *rd_in_receives = NULL, *rd_out_requests = NULL, *rd_forward_datagrams = NULL,
2061                               *rd_in_delivers = NULL;
2062
2063                 if (unlikely(!st)) {
2064                     st = rrdset_create_localhost("ipv4",
2065                                                  "packets",
2066                                                  NULL,
2067                                                  "packets",
2068                                                  NULL,
2069                                                  "IPv4 Packets",
2070                                                  "packets/s",
2071                                                  3000,
2072                                                  update_every,
2073                                                  RRDSET_TYPE_LINE
2074                     );
2075
2076                     rd_in_receives       = rrddim_add(st, "InReceives",    "received",  1, 1, RRD_ALGORITHM_INCREMENTAL);
2077                     rd_out_requests      = rrddim_add(st, "OutRequests",   "sent",     -1, 1, RRD_ALGORITHM_INCREMENTAL);
2078                     rd_forward_datagrams = rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRD_ALGORITHM_INCREMENTAL);
2079                     rd_in_delivers       = rrddim_add(st, "InDelivers",    "delivered", 1, 1, RRD_ALGORITHM_INCREMENTAL);
2080                 } else
2081                     rrdset_next(st);
2082
2083                 rrddim_set_by_pointer(st, rd_in_receives,       ipstat.ips_total);
2084                 rrddim_set_by_pointer(st, rd_out_requests,      ipstat.ips_localout);
2085                 rrddim_set_by_pointer(st, rd_forward_datagrams, ipstat.ips_forward);
2086                 rrddim_set_by_pointer(st, rd_in_delivers,       ipstat.ips_delivered);
2087                 rrdset_done(st);
2088             }
2089
2090             // --------------------------------------------------------------------
2091
2092             if (likely(do_ip_fragsout)) {
2093                 static RRDSET *st = NULL;
2094                 static RRDDIM *rd_ok = NULL, *rd_fails = NULL, *rd_created = NULL;
2095
2096                 if (unlikely(!st)) {
2097                     st = rrdset_create_localhost("ipv4",
2098                                                  "fragsout",
2099                                                  NULL,
2100                                                  "fragments",
2101                                                  NULL,
2102                                                  "IPv4 Fragments Sent",
2103                                                  "packets/s",
2104                                                  3010,
2105                                                  update_every,
2106                                                  RRDSET_TYPE_LINE
2107                     );
2108
2109                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
2110
2111                     rd_ok      = rrddim_add(st, "FragOKs",     "ok",      1, 1, RRD_ALGORITHM_INCREMENTAL);
2112                     rd_fails   = rrddim_add(st, "FragFails",   "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
2113                     rd_created = rrddim_add(st, "FragCreates", "created", 1, 1, RRD_ALGORITHM_INCREMENTAL);
2114                 } else
2115                     rrdset_next(st);
2116
2117                 rrddim_set_by_pointer(st, rd_ok,      ipstat.ips_fragmented);
2118                 rrddim_set_by_pointer(st, rd_fails,   ipstat.ips_cantfrag);
2119                 rrddim_set_by_pointer(st, rd_created, ipstat.ips_ofragments);
2120                 rrdset_done(st);
2121             }
2122
2123             // --------------------------------------------------------------------
2124
2125             if (likely(do_ip_fragsin)) {
2126                 static RRDSET *st = NULL;
2127                 static RRDDIM *rd_ok = NULL, *rd_failed = NULL, *rd_all = NULL;
2128
2129                 if (unlikely(!st)) {
2130                     st = rrdset_create_localhost("ipv4",
2131                                                  "fragsin",
2132                                                  NULL,
2133                                                  "fragments",
2134                                                  NULL,
2135                                                  "IPv4 Fragments Reassembly",
2136                                                  "packets/s",
2137                                                  3011,
2138                                                  update_every,
2139                                                  RRDSET_TYPE_LINE
2140                     );
2141
2142                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
2143
2144                     rd_ok     = rrddim_add(st, "ReasmOKs",   "ok",      1, 1, RRD_ALGORITHM_INCREMENTAL);
2145                     rd_failed = rrddim_add(st, "ReasmFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
2146                     rd_all    = rrddim_add(st, "ReasmReqds", "all",     1, 1, RRD_ALGORITHM_INCREMENTAL);
2147                 } else
2148                     rrdset_next(st);
2149
2150                 rrddim_set_by_pointer(st, rd_ok,     ipstat.ips_fragments);
2151                 rrddim_set_by_pointer(st, rd_failed, ipstat.ips_fragdropped);
2152                 rrddim_set_by_pointer(st, rd_all,    ipstat.ips_reassembled);
2153                 rrdset_done(st);
2154             }
2155
2156             // --------------------------------------------------------------------
2157
2158             if (likely(do_ip_errors)) {
2159                 static RRDSET *st = NULL;
2160                 static RRDDIM *rd_in_discards = NULL, *rd_out_discards = NULL,
2161                               *rd_in_hdr_errors = NULL, *rd_out_no_routes = NULL,
2162                               *rd_in_addr_errors = NULL, *rd_in_unknown_protos = NULL;
2163
2164                 if (unlikely(!st)) {
2165                     st = rrdset_create_localhost("ipv4",
2166                                                  "errors",
2167                                                  NULL,
2168                                                  "errors",
2169                                                  NULL,
2170                                                  "IPv4 Errors",
2171                                                  "packets/s",
2172                                                  3002,
2173                                                  update_every,
2174                                                  RRDSET_TYPE_LINE
2175                     );
2176
2177                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
2178
2179                     rd_in_discards       = rrddim_add(st, "InDiscards",      NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2180                     rd_out_discards      = rrddim_add(st, "OutDiscards",     NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2181                     rd_in_hdr_errors     = rrddim_add(st, "InHdrErrors",     NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2182                     rd_out_no_routes     = rrddim_add(st, "OutNoRoutes",     NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2183                     rd_in_addr_errors    = rrddim_add(st, "InAddrErrors",    NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2184                     rd_in_unknown_protos = rrddim_add(st, "InUnknownProtos", NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2185                 } else
2186                     rrdset_next(st);
2187
2188                 rrddim_set_by_pointer(st, rd_in_discards,       ipstat.ips_badsum + ipstat.ips_tooshort +
2189                                                                 ipstat.ips_toosmall + ipstat.ips_toolong);
2190                 rrddim_set_by_pointer(st, rd_out_discards,      ipstat.ips_odropped);
2191                 rrddim_set_by_pointer(st, rd_in_hdr_errors,     ipstat.ips_badhlen + ipstat.ips_badlen +
2192                                                                 ipstat.ips_badoptions + ipstat.ips_badvers);
2193                 rrddim_set_by_pointer(st, rd_out_no_routes,     ipstat.ips_noroute);
2194                 rrddim_set_by_pointer(st, rd_in_addr_errors,    ipstat.ips_badaddr);
2195                 rrddim_set_by_pointer(st, rd_in_unknown_protos, ipstat.ips_noproto);
2196                 rrdset_done(st);
2197             }
2198         }
2199     } else {
2200         error("DISABLED: net.inet.ip.stats module");
2201         return 1;
2202     }
2203
2204     return 0;
2205 }
2206
2207 // --------------------------------------------------------------------------------------------------------------------
2208 // net.inet6.ip6.stats
2209
2210 int do_net_inet6_ip6_stats(int update_every, usec_t dt) {
2211     (void)dt;
2212     static int do_ip6_packets = -1, do_ip6_fragsout = -1, do_ip6_fragsin = -1, do_ip6_errors = -1;
2213
2214     if (unlikely(do_ip6_packets == -1)) {
2215         do_ip6_packets  = config_get_boolean_ondemand("plugin:freebsd:net.inet6.ip6.stats", "ipv6 packets",
2216                                                       CONFIG_BOOLEAN_AUTO);
2217         do_ip6_fragsout = config_get_boolean_ondemand("plugin:freebsd:net.inet6.ip6.stats", "ipv6 fragments sent",
2218                                                       CONFIG_BOOLEAN_AUTO);
2219         do_ip6_fragsin  = config_get_boolean_ondemand("plugin:freebsd:net.inet6.ip6.stats", "ipv6 fragments assembly",
2220                                                       CONFIG_BOOLEAN_AUTO);
2221         do_ip6_errors   = config_get_boolean_ondemand("plugin:freebsd:net.inet6.ip6.stats", "ipv6 errors",
2222                                                       CONFIG_BOOLEAN_AUTO);
2223     }
2224
2225     if (likely(do_ip6_packets || do_ip6_fragsout || do_ip6_fragsin || do_ip6_errors)) {
2226         static int mib[4] = {0, 0, 0, 0};
2227         struct ip6stat ip6stat;
2228
2229         if (unlikely(GETSYSCTL_SIMPLE("net.inet6.ip6.stats", mib, ip6stat))) {
2230             do_ip6_packets = 0;
2231             error("DISABLED: ipv6.packets chart");
2232             do_ip6_fragsout = 0;
2233             error("DISABLED: ipv6.fragsout chart");
2234             do_ip6_fragsin = 0;
2235             error("DISABLED: ipv6.fragsin chart");
2236             do_ip6_errors = 0;
2237             error("DISABLED: ipv6.errors chart");
2238             error("DISABLED: net.inet6.ip6.stats module");
2239             return 1;
2240         } else {
2241
2242             // --------------------------------------------------------------------
2243
2244             if (do_ip6_packets == CONFIG_BOOLEAN_YES || (do_ip6_packets == CONFIG_BOOLEAN_AUTO &&
2245                                                          (ip6stat.ip6s_localout || ip6stat.ip6s_total ||
2246                                                           ip6stat.ip6s_forward || ip6stat.ip6s_delivered))) {
2247                 do_ip6_packets = CONFIG_BOOLEAN_YES;
2248
2249                 static RRDSET *st = NULL;
2250                 static RRDDIM *rd_received = NULL, *rd_sent = NULL, *rd_forwarded = NULL, *rd_delivers = NULL;
2251
2252                 if (unlikely(!st)) {
2253                     st = rrdset_create_localhost("ipv6",
2254                                                  "packets",
2255                                                  NULL,
2256                                                  "packets",
2257                                                  NULL,
2258                                                  "IPv6 Packets",
2259                                                  "packets/s",
2260                                                  3000,
2261                                                  update_every,
2262                                                  RRDSET_TYPE_LINE
2263                     );
2264
2265                     rd_received  = rrddim_add(st, "received",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2266                     rd_sent      = rrddim_add(st, "sent",      NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2267                     rd_forwarded = rrddim_add(st, "forwarded", NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2268                     rd_delivers  = rrddim_add(st, "delivers",  NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2269                 } else
2270                     rrdset_next(st);
2271
2272                 rrddim_set_by_pointer(st, rd_sent,      ip6stat.ip6s_localout);
2273                 rrddim_set_by_pointer(st, rd_received,  ip6stat.ip6s_total);
2274                 rrddim_set_by_pointer(st, rd_forwarded, ip6stat.ip6s_forward);
2275                 rrddim_set_by_pointer(st, rd_delivers,  ip6stat.ip6s_delivered);
2276                 rrdset_done(st);
2277             }
2278
2279             // --------------------------------------------------------------------
2280
2281             if (do_ip6_fragsout == CONFIG_BOOLEAN_YES || (do_ip6_fragsout == CONFIG_BOOLEAN_AUTO &&
2282                                                           (ip6stat.ip6s_fragmented || ip6stat.ip6s_cantfrag ||
2283                                                            ip6stat.ip6s_ofragments))) {
2284                 do_ip6_fragsout = CONFIG_BOOLEAN_YES;
2285
2286                 static RRDSET *st = NULL;
2287                 static RRDDIM *rd_ok = NULL, *rd_failed = NULL, *rd_all = NULL;
2288
2289                 if (unlikely(!st)) {
2290                     st = rrdset_create_localhost("ipv6",
2291                                                  "fragsout",
2292                                                  NULL,
2293                                                  "fragments",
2294                                                  NULL,
2295                                                  "IPv6 Fragments Sent",
2296                                                  "packets/s",
2297                                                  3010,
2298                                                  update_every,
2299                                                  RRDSET_TYPE_LINE
2300                     );
2301
2302                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
2303
2304                     rd_ok     = rrddim_add(st, "ok",     NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2305                     rd_failed = rrddim_add(st, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2306                     rd_all    = rrddim_add(st, "all",    NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2307                 } else
2308                     rrdset_next(st);
2309
2310                 rrddim_set_by_pointer(st, rd_ok,     ip6stat.ip6s_fragmented);
2311                 rrddim_set_by_pointer(st, rd_failed, ip6stat.ip6s_cantfrag);
2312                 rrddim_set_by_pointer(st, rd_all,    ip6stat.ip6s_ofragments);
2313                 rrdset_done(st);
2314             }
2315
2316             // --------------------------------------------------------------------
2317
2318             if (do_ip6_fragsin == CONFIG_BOOLEAN_YES || (do_ip6_fragsin == CONFIG_BOOLEAN_AUTO &&
2319                                                          (ip6stat.ip6s_reassembled || ip6stat.ip6s_fragdropped ||
2320                                                           ip6stat.ip6s_fragtimeout || ip6stat.ip6s_fragments))) {
2321                 do_ip6_fragsin = CONFIG_BOOLEAN_YES;
2322
2323                 static RRDSET *st = NULL;
2324                 static RRDDIM *rd_ok = NULL, *rd_failed = NULL, *rd_timeout = NULL, *rd_all = NULL;
2325
2326                 if (unlikely(!st)) {
2327                     st = rrdset_create_localhost("ipv6",
2328                                                  "fragsin",
2329                                                  NULL,
2330                                                  "fragments",
2331                                                  NULL,
2332                                                  "IPv6 Fragments Reassembly",
2333                                                  "packets/s",
2334                                                  3011,
2335                                                  update_every,
2336                                                  RRDSET_TYPE_LINE
2337                     );
2338
2339                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
2340
2341                     rd_ok      = rrddim_add(st, "ok",      NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2342                     rd_failed  = rrddim_add(st, "failed",  NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2343                     rd_timeout = rrddim_add(st, "timeout", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2344                     rd_all     = rrddim_add(st, "all",     NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2345                 } else
2346                     rrdset_next(st);
2347
2348                 rrddim_set_by_pointer(st, rd_ok,      ip6stat.ip6s_reassembled);
2349                 rrddim_set_by_pointer(st, rd_failed,  ip6stat.ip6s_fragdropped);
2350                 rrddim_set_by_pointer(st, rd_timeout, ip6stat.ip6s_fragtimeout);
2351                 rrddim_set_by_pointer(st, rd_all,     ip6stat.ip6s_fragments);
2352                 rrdset_done(st);
2353             }
2354
2355             // --------------------------------------------------------------------
2356
2357             if (do_ip6_errors == CONFIG_BOOLEAN_YES || (do_ip6_errors == CONFIG_BOOLEAN_AUTO && (
2358                     ip6stat.ip6s_toosmall ||
2359                     ip6stat.ip6s_odropped ||
2360                     ip6stat.ip6s_badoptions ||
2361                     ip6stat.ip6s_badvers ||
2362                     ip6stat.ip6s_exthdrtoolong ||
2363                     ip6stat.ip6s_sources_none ||
2364                     ip6stat.ip6s_tooshort ||
2365                     ip6stat.ip6s_cantforward ||
2366                     ip6stat.ip6s_noroute))) {
2367                 do_ip6_errors = CONFIG_BOOLEAN_YES;
2368
2369                 static RRDSET *st = NULL;
2370                 static RRDDIM *rd_in_discards = NULL, *rd_out_discards = NULL,
2371                               *rd_in_hdr_errors = NULL, *rd_in_addr_errors = NULL, *rd_in_truncated_pkts = NULL,
2372                               *rd_in_no_routes = NULL, *rd_out_no_routes = NULL;
2373
2374                 if (unlikely(!st)) {
2375                     st = rrdset_create_localhost("ipv6",
2376                                                  "errors",
2377                                                  NULL,
2378                                                  "errors",
2379                                                  NULL,
2380                                                  "IPv6 Errors",
2381                                                  "packets/s",
2382                                                  3002,
2383                                                  update_every,
2384                                                  RRDSET_TYPE_LINE
2385                     );
2386
2387                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
2388
2389                     rd_in_discards       = rrddim_add(st, "InDiscards",      NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2390                     rd_out_discards      = rrddim_add(st, "OutDiscards",     NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2391                     rd_in_hdr_errors     = rrddim_add(st, "InHdrErrors",     NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2392                     rd_in_addr_errors    = rrddim_add(st, "InAddrErrors",    NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2393                     rd_in_truncated_pkts = rrddim_add(st, "InTruncatedPkts", NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2394                     rd_in_no_routes      = rrddim_add(st, "InNoRoutes",      NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2395                     rd_out_no_routes     = rrddim_add(st, "OutNoRoutes",     NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2396                 } else
2397                     rrdset_next(st);
2398
2399                 rrddim_set_by_pointer(st, rd_in_discards,       ip6stat.ip6s_toosmall);
2400                 rrddim_set_by_pointer(st, rd_out_discards,      ip6stat.ip6s_odropped);
2401                 rrddim_set_by_pointer(st, rd_in_hdr_errors,     ip6stat.ip6s_badoptions + ip6stat.ip6s_badvers +
2402                                                                 ip6stat.ip6s_exthdrtoolong);
2403                 rrddim_set_by_pointer(st, rd_in_addr_errors,    ip6stat.ip6s_sources_none);
2404                 rrddim_set_by_pointer(st, rd_in_truncated_pkts, ip6stat.ip6s_tooshort);
2405                 rrddim_set_by_pointer(st, rd_in_no_routes,      ip6stat.ip6s_cantforward);
2406                 rrddim_set_by_pointer(st, rd_out_no_routes,     ip6stat.ip6s_noroute);
2407                 rrdset_done(st);
2408             }
2409         }
2410     } else {
2411         error("DISABLED: net.inet6.ip6.stats module");
2412         return 1;
2413     }
2414
2415     return 0;
2416 }
2417
2418 // --------------------------------------------------------------------------------------------------------------------
2419 // net.inet6.icmp6.stats
2420
2421 int do_net_inet6_icmp6_stats(int update_every, usec_t dt) {
2422     (void)dt;
2423     static int do_icmp6 = -1, do_icmp6_redir = -1, do_icmp6_errors = -1, do_icmp6_echos = -1, do_icmp6_router = -1,
2424             do_icmp6_neighbor = -1, do_icmp6_types = -1;
2425
2426     if (unlikely(do_icmp6 == -1)) {
2427         do_icmp6          = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp",
2428                                                         CONFIG_BOOLEAN_AUTO);
2429         do_icmp6_redir    = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp redirects",
2430                                                         CONFIG_BOOLEAN_AUTO);
2431         do_icmp6_errors   = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp errors",
2432                                                         CONFIG_BOOLEAN_AUTO);
2433         do_icmp6_echos    = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp echos",
2434                                                         CONFIG_BOOLEAN_AUTO);
2435         do_icmp6_router   = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp router",
2436                                                         CONFIG_BOOLEAN_AUTO);
2437         do_icmp6_neighbor = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp neighbor",
2438                                                         CONFIG_BOOLEAN_AUTO);
2439         do_icmp6_types    = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp types",
2440                                                         CONFIG_BOOLEAN_AUTO);
2441     }
2442
2443     if (likely(do_icmp6 || do_icmp6_redir || do_icmp6_errors || do_icmp6_echos || do_icmp6_router || do_icmp6_neighbor || do_icmp6_types)) {
2444         static int mib[4] = {0, 0, 0, 0};
2445         struct icmp6stat icmp6stat;
2446
2447         if (unlikely(GETSYSCTL_SIMPLE("net.inet6.icmp6.stats", mib, icmp6stat))) {
2448             do_icmp6 = 0;
2449             error("DISABLED: ipv6.icmp chart");
2450             do_icmp6_redir = 0;
2451             error("DISABLED: ipv6.icmpredir chart");
2452             do_icmp6_errors = 0;
2453             error("DISABLED: ipv6.icmperrors chart");
2454             do_icmp6_echos = 0;
2455             error("DISABLED: ipv6.icmpechos chart");
2456             do_icmp6_router = 0;
2457             error("DISABLED: ipv6.icmprouter chart");
2458             do_icmp6_neighbor = 0;
2459             error("DISABLED: ipv6.icmpneighbor chart");
2460             do_icmp6_types = 0;
2461             error("DISABLED: ipv6.icmptypes chart");
2462             error("DISABLED: net.inet6.icmp6.stats module");
2463             return 1;
2464         } else {
2465             int i;
2466             struct icmp6_total {
2467                 u_long  msgs_in;
2468                 u_long  msgs_out;
2469             } icmp6_total = {0, 0};
2470
2471             for (i = 0; i <= ICMP6_MAXTYPE; i++) {
2472                 icmp6_total.msgs_in += icmp6stat.icp6s_inhist[i];
2473                 icmp6_total.msgs_out += icmp6stat.icp6s_outhist[i];
2474             }
2475             icmp6_total.msgs_in += icmp6stat.icp6s_badcode + icmp6stat.icp6s_badlen + icmp6stat.icp6s_checksum + icmp6stat.icp6s_tooshort;
2476
2477             // --------------------------------------------------------------------
2478
2479             if (do_icmp6 == CONFIG_BOOLEAN_YES || (do_icmp6 == CONFIG_BOOLEAN_AUTO && (icmp6_total.msgs_in || icmp6_total.msgs_out))) {
2480                 do_icmp6 = CONFIG_BOOLEAN_YES;
2481
2482                 static RRDSET *st = NULL;
2483                 static RRDDIM *rd_received = NULL, *rd_sent = NULL;
2484
2485                 if (unlikely(!st)) {
2486                     st = rrdset_create_localhost("ipv6",
2487                                                  "icmp",
2488                                                  NULL,
2489                                                  "icmp",
2490                                                  NULL,
2491                                                  "IPv6 ICMP Messages",
2492                                                  "messages/s",
2493                                                  10000,
2494                                                  update_every,
2495                                                  RRDSET_TYPE_LINE
2496                     );
2497
2498                     rd_received = rrddim_add(st, "received", NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2499                     rd_sent     = rrddim_add(st, "sent",     NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2500                 } else
2501                     rrdset_next(st);
2502
2503                 rrddim_set_by_pointer(st, rd_received, icmp6_total.msgs_out);
2504                 rrddim_set_by_pointer(st, rd_sent,     icmp6_total.msgs_in);
2505
2506                 rrdset_done(st);
2507             }
2508
2509             // --------------------------------------------------------------------
2510
2511             if (do_icmp6_redir == CONFIG_BOOLEAN_YES || (do_icmp6_redir == CONFIG_BOOLEAN_AUTO && (icmp6stat.icp6s_inhist[ND_REDIRECT] || icmp6stat.icp6s_outhist[ND_REDIRECT]))) {
2512                 do_icmp6_redir = CONFIG_BOOLEAN_YES;
2513
2514                 static RRDSET *st = NULL;
2515                 static RRDDIM *rd_received = NULL, *rd_sent = NULL;
2516
2517                 if (unlikely(!st)) {
2518                     st = rrdset_create_localhost("ipv6",
2519                                                  "icmpredir",
2520                                                  NULL,
2521                                                  "icmp",
2522                                                  NULL,
2523                                                  "IPv6 ICMP Redirects",
2524                                                  "redirects/s",
2525                                                  10050,
2526                                                  update_every,
2527                                                  RRDSET_TYPE_LINE
2528                     );
2529
2530                     rd_received = rrddim_add(st, "received", NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2531                     rd_sent     = rrddim_add(st, "sent",     NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2532                 } else
2533                     rrdset_next(st);
2534
2535                 rrddim_set_by_pointer(st, rd_received, icmp6stat.icp6s_outhist[ND_REDIRECT]);
2536                 rrddim_set_by_pointer(st, rd_sent, icmp6stat.icp6s_inhist[ND_REDIRECT]);
2537                 rrdset_done(st);
2538             }
2539
2540             // --------------------------------------------------------------------
2541
2542             if (do_icmp6_errors == CONFIG_BOOLEAN_YES || (do_icmp6_errors == CONFIG_BOOLEAN_AUTO && (
2543                     icmp6stat.icp6s_badcode ||
2544                     icmp6stat.icp6s_badlen ||
2545                     icmp6stat.icp6s_checksum ||
2546                     icmp6stat.icp6s_tooshort ||
2547                     icmp6stat.icp6s_error ||
2548                     icmp6stat.icp6s_inhist[ICMP6_DST_UNREACH] ||
2549                     icmp6stat.icp6s_inhist[ICMP6_TIME_EXCEEDED] ||
2550                     icmp6stat.icp6s_inhist[ICMP6_PARAM_PROB] ||
2551                     icmp6stat.icp6s_outhist[ICMP6_DST_UNREACH] ||
2552                     icmp6stat.icp6s_outhist[ICMP6_TIME_EXCEEDED] ||
2553                     icmp6stat.icp6s_outhist[ICMP6_PARAM_PROB]))) {
2554                 do_icmp6_errors = CONFIG_BOOLEAN_YES;
2555
2556                 static RRDSET *st = NULL;
2557                 static RRDDIM *rd_in_errors = NULL, *rd_out_errors = NULL, *rd_in_csum_errors = NULL,
2558                               *rd_in_dest_unreachs = NULL, *rd_in_pkt_too_bigs = NULL, *rd_in_time_excds = NULL,
2559                               *rd_in_parm_problems = NULL, *rd_out_dest_unreachs = NULL, *rd_out_time_excds = NULL,
2560                               *rd_out_parm_problems = NULL;
2561
2562                 if (unlikely(!st)) {
2563                     st = rrdset_create_localhost("ipv6",
2564                                                  "icmperrors",
2565                                                  NULL, "icmp",
2566                                                  NULL,
2567                                                  "IPv6 ICMP Errors",
2568                                                  "errors/s",
2569                                                  10100,
2570                                                  update_every,
2571                                                  RRDSET_TYPE_LINE
2572                     );
2573
2574                     rd_in_errors         = rrddim_add(st, "InErrors",        NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2575                     rd_out_errors        = rrddim_add(st, "OutErrors",       NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2576                     rd_in_csum_errors    = rrddim_add(st, "InCsumErrors",    NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2577                     rd_in_dest_unreachs  = rrddim_add(st, "InDestUnreachs",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2578                     rd_in_pkt_too_bigs   = rrddim_add(st, "InPktTooBigs",    NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2579                     rd_in_time_excds     = rrddim_add(st, "InTimeExcds",     NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2580                     rd_in_parm_problems  = rrddim_add(st, "InParmProblems",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2581                     rd_out_dest_unreachs = rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2582                     rd_out_time_excds    = rrddim_add(st, "OutTimeExcds",    NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2583                     rd_out_parm_problems = rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2584                 } else
2585                     rrdset_next(st);
2586
2587                 rrddim_set_by_pointer(st, rd_in_errors,         icmp6stat.icp6s_badcode + icmp6stat.icp6s_badlen +
2588                                                                 icmp6stat.icp6s_checksum + icmp6stat.icp6s_tooshort);
2589                 rrddim_set_by_pointer(st, rd_out_errors,        icmp6stat.icp6s_error);
2590                 rrddim_set_by_pointer(st, rd_in_csum_errors,    icmp6stat.icp6s_checksum);
2591                 rrddim_set_by_pointer(st, rd_in_dest_unreachs,  icmp6stat.icp6s_inhist[ICMP6_DST_UNREACH]);
2592                 rrddim_set_by_pointer(st, rd_in_pkt_too_bigs,   icmp6stat.icp6s_badlen);
2593                 rrddim_set_by_pointer(st, rd_in_time_excds,     icmp6stat.icp6s_inhist[ICMP6_TIME_EXCEEDED]);
2594                 rrddim_set_by_pointer(st, rd_in_parm_problems,  icmp6stat.icp6s_inhist[ICMP6_PARAM_PROB]);
2595                 rrddim_set_by_pointer(st, rd_out_dest_unreachs, icmp6stat.icp6s_outhist[ICMP6_DST_UNREACH]);
2596                 rrddim_set_by_pointer(st, rd_out_time_excds,    icmp6stat.icp6s_outhist[ICMP6_TIME_EXCEEDED]);
2597                 rrddim_set_by_pointer(st, rd_out_parm_problems, icmp6stat.icp6s_outhist[ICMP6_PARAM_PROB]);
2598                 rrdset_done(st);
2599             }
2600
2601             // --------------------------------------------------------------------
2602
2603             if (do_icmp6_echos == CONFIG_BOOLEAN_YES || (do_icmp6_echos == CONFIG_BOOLEAN_AUTO && (
2604                     icmp6stat.icp6s_inhist[ICMP6_ECHO_REQUEST] ||
2605                     icmp6stat.icp6s_outhist[ICMP6_ECHO_REQUEST] ||
2606                     icmp6stat.icp6s_inhist[ICMP6_ECHO_REPLY] ||
2607                     icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]))) {
2608                 do_icmp6_echos = CONFIG_BOOLEAN_YES;
2609
2610                 static RRDSET *st = NULL;
2611                 static RRDDIM *rd_in = NULL, *rd_out = NULL, *rd_in_replies = NULL, *rd_out_replies = NULL;
2612
2613                 if (unlikely(!st)) {
2614                     st = rrdset_create_localhost("ipv6",
2615                                                  "icmpechos",
2616                                                  NULL,
2617                                                  "icmp",
2618                                                  NULL,
2619                                                  "IPv6 ICMP Echo",
2620                                                  "messages/s",
2621                                                  10200,
2622                                                  update_every,
2623                                                  RRDSET_TYPE_LINE
2624                     );
2625
2626                     rd_in          = rrddim_add(st, "InEchos",        NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2627                     rd_out         = rrddim_add(st, "OutEchos",       NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2628                     rd_in_replies  = rrddim_add(st, "InEchoReplies",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2629                     rd_out_replies = rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2630                 } else
2631                     rrdset_next(st);
2632
2633                 rrddim_set_by_pointer(st, rd_in,          icmp6stat.icp6s_inhist[ICMP6_ECHO_REQUEST]);
2634                 rrddim_set_by_pointer(st, rd_out,         icmp6stat.icp6s_outhist[ICMP6_ECHO_REQUEST]);
2635                 rrddim_set_by_pointer(st, rd_in_replies,  icmp6stat.icp6s_inhist[ICMP6_ECHO_REPLY]);
2636                 rrddim_set_by_pointer(st, rd_out_replies, icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]);
2637                 rrdset_done(st);
2638             }
2639
2640             // --------------------------------------------------------------------
2641
2642             if (do_icmp6_router == CONFIG_BOOLEAN_YES || (do_icmp6_router == CONFIG_BOOLEAN_AUTO && (
2643                     icmp6stat.icp6s_inhist[ND_ROUTER_SOLICIT] ||
2644                     icmp6stat.icp6s_outhist[ND_ROUTER_SOLICIT] ||
2645                     icmp6stat.icp6s_inhist[ND_ROUTER_ADVERT] ||
2646                     icmp6stat.icp6s_outhist[ND_ROUTER_ADVERT]))) {
2647                 do_icmp6_router = CONFIG_BOOLEAN_YES;
2648
2649                 static RRDSET *st = NULL;
2650                 static RRDDIM *rd_in_solicits = NULL, *rd_out_solicits = NULL,
2651                               *rd_in_advertisements = NULL, *rd_out_advertisements = NULL;
2652
2653                 if (unlikely(!st)) {
2654                     st = rrdset_create_localhost("ipv6",
2655                                                  "icmprouter",
2656                                                  NULL,
2657                                                  "icmp",
2658                                                  NULL,
2659                                                  "IPv6 Router Messages",
2660                                                  "messages/s",
2661                                                  10400,
2662                                                  update_every,
2663                                                  RRDSET_TYPE_LINE
2664                     );
2665
2666                     rd_in_solicits        = rrddim_add(st, "InSolicits",        NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2667                     rd_out_solicits       = rrddim_add(st, "OutSolicits",       NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2668                     rd_in_advertisements  = rrddim_add(st, "InAdvertisements",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2669                     rd_out_advertisements = rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2670                 } else
2671                     rrdset_next(st);
2672
2673                 rrddim_set_by_pointer(st, rd_in_solicits,        icmp6stat.icp6s_inhist[ND_ROUTER_SOLICIT]);
2674                 rrddim_set_by_pointer(st, rd_out_solicits,       icmp6stat.icp6s_outhist[ND_ROUTER_SOLICIT]);
2675                 rrddim_set_by_pointer(st, rd_in_advertisements,  icmp6stat.icp6s_inhist[ND_ROUTER_ADVERT]);
2676                 rrddim_set_by_pointer(st, rd_out_advertisements, icmp6stat.icp6s_outhist[ND_ROUTER_ADVERT]);
2677                 rrdset_done(st);
2678             }
2679
2680             // --------------------------------------------------------------------
2681
2682             if (do_icmp6_neighbor == CONFIG_BOOLEAN_YES || (do_icmp6_neighbor == CONFIG_BOOLEAN_AUTO && (
2683                     icmp6stat.icp6s_inhist[ND_NEIGHBOR_SOLICIT] ||
2684                     icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT] ||
2685                     icmp6stat.icp6s_inhist[ND_NEIGHBOR_ADVERT] ||
2686                     icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]))) {
2687                 do_icmp6_neighbor = CONFIG_BOOLEAN_YES;
2688
2689                 static RRDSET *st = NULL;
2690                 static RRDDIM *rd_in_solicits = NULL, *rd_out_solicits = NULL,
2691                               *rd_in_advertisements = NULL, *rd_out_advertisements = NULL;
2692
2693                 if (unlikely(!st)) {
2694                     st = rrdset_create_localhost("ipv6",
2695                                                  "icmpneighbor",
2696                                                  NULL,
2697                                                  "icmp",
2698                                                  NULL,
2699                                                  "IPv6 Neighbor Messages",
2700                                                  "messages/s",
2701                                                  10500,
2702                                                  update_every,
2703                                                  RRDSET_TYPE_LINE
2704                     );
2705
2706                     rd_in_solicits        = rrddim_add(st, "InSolicits",        NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2707                     rd_out_solicits       = rrddim_add(st, "OutSolicits",       NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2708                     rd_in_advertisements  = rrddim_add(st, "InAdvertisements",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2709                     rd_out_advertisements = rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2710                 } else
2711                     rrdset_next(st);
2712
2713                 rrddim_set_by_pointer(st, rd_in_solicits,        icmp6stat.icp6s_inhist[ND_NEIGHBOR_SOLICIT]);
2714                 rrddim_set_by_pointer(st, rd_out_solicits,       icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT]);
2715                 rrddim_set_by_pointer(st, rd_in_advertisements,  icmp6stat.icp6s_inhist[ND_NEIGHBOR_ADVERT]);
2716                 rrddim_set_by_pointer(st, rd_out_advertisements, icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]);
2717                 rrdset_done(st);
2718             }
2719
2720             // --------------------------------------------------------------------
2721
2722             if (do_icmp6_types == CONFIG_BOOLEAN_YES || (do_icmp6_types == CONFIG_BOOLEAN_AUTO && (
2723                     icmp6stat.icp6s_inhist[1] ||
2724                     icmp6stat.icp6s_inhist[128] ||
2725                     icmp6stat.icp6s_inhist[129] ||
2726                     icmp6stat.icp6s_inhist[136] ||
2727                     icmp6stat.icp6s_outhist[1] ||
2728                     icmp6stat.icp6s_outhist[128] ||
2729                     icmp6stat.icp6s_outhist[129] ||
2730                     icmp6stat.icp6s_outhist[133] ||
2731                     icmp6stat.icp6s_outhist[135] ||
2732                     icmp6stat.icp6s_outhist[136]))) {
2733                 do_icmp6_types = CONFIG_BOOLEAN_YES;
2734
2735                 static RRDSET *st = NULL;
2736                 static RRDDIM *rd_in_1 = NULL, *rd_in_128 = NULL, *rd_in_129 = NULL, *rd_in_136 = NULL,
2737                               *rd_out_1 = NULL, *rd_out_128 = NULL, *rd_out_129 = NULL, *rd_out_133 = NULL,
2738                               *rd_out_135 = NULL, *rd_out_143 = NULL;
2739
2740                 if (unlikely(!st)) {
2741                     st = rrdset_create_localhost("ipv6",
2742                                                  "icmptypes",
2743                                                  NULL,
2744                                                  "icmp",
2745                                                  NULL,
2746                                                  "IPv6 ICMP Types",
2747                                                  "messages/s",
2748                                                  10700,
2749                                                  update_every,
2750                                                  RRDSET_TYPE_LINE
2751                     );
2752
2753                     rd_in_1    = rrddim_add(st, "InType1",    NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2754                     rd_in_128  = rrddim_add(st, "InType128",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2755                     rd_in_129  = rrddim_add(st, "InType129",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2756                     rd_in_136  = rrddim_add(st, "InType136",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
2757                     rd_out_1   = rrddim_add(st, "OutType1",   NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2758                     rd_out_128 = rrddim_add(st, "OutType128", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2759                     rd_out_129 = rrddim_add(st, "OutType129", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2760                     rd_out_133 = rrddim_add(st, "OutType133", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2761                     rd_out_135 = rrddim_add(st, "OutType135", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2762                     rd_out_143 = rrddim_add(st, "OutType143", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2763                 } else
2764                     rrdset_next(st);
2765
2766                 rrddim_set_by_pointer(st, rd_in_1,    icmp6stat.icp6s_inhist[1]);
2767                 rrddim_set_by_pointer(st, rd_in_128,  icmp6stat.icp6s_inhist[128]);
2768                 rrddim_set_by_pointer(st, rd_in_129,  icmp6stat.icp6s_inhist[129]);
2769                 rrddim_set_by_pointer(st, rd_in_136,  icmp6stat.icp6s_inhist[136]);
2770                 rrddim_set_by_pointer(st, rd_out_1,   icmp6stat.icp6s_outhist[1]);
2771                 rrddim_set_by_pointer(st, rd_out_128, icmp6stat.icp6s_outhist[128]);
2772                 rrddim_set_by_pointer(st, rd_out_129, icmp6stat.icp6s_outhist[129]);
2773                 rrddim_set_by_pointer(st, rd_out_133, icmp6stat.icp6s_outhist[133]);
2774                 rrddim_set_by_pointer(st, rd_out_135, icmp6stat.icp6s_outhist[135]);
2775                 rrddim_set_by_pointer(st, rd_out_143, icmp6stat.icp6s_outhist[143]);
2776                 rrdset_done(st);
2777             }
2778         }
2779     } else {
2780         error("DISABLED: net.inet6.icmp6.stats module");
2781         return 1;
2782     }
2783
2784     return 0;
2785 }
2786
2787 // --------------------------------------------------------------------------------------------------------------------
2788 // getmntinfo
2789
2790 int do_getmntinfo(int update_every, usec_t dt) {
2791     (void)dt;
2792
2793 #define DELAULT_EXLUDED_PATHS "/proc/*"
2794 // taken from gnulib/mountlist.c and shortened to FreeBSD related fstypes
2795 #define DEFAULT_EXCLUDED_FILESYSTEMS "autofs procfs subfs devfs none"
2796 #define CONFIG_SECTION_GETMNTINFO "plugin:freebsd:getmntinfo"
2797
2798     static int do_space = -1, do_inodes = -1;
2799
2800     if (unlikely(do_space == -1)) {
2801         do_space  = config_get_boolean_ondemand(CONFIG_SECTION_GETMNTINFO, "space usage for all disks",  CONFIG_BOOLEAN_AUTO);
2802         do_inodes = config_get_boolean_ondemand(CONFIG_SECTION_GETMNTINFO, "inodes usage for all disks", CONFIG_BOOLEAN_AUTO);
2803     }
2804
2805     if (likely(do_space || do_inodes)) {
2806         struct statfs *mntbuf;
2807         int mntsize;
2808
2809         // there is no mount info in sysctl MIBs
2810         if (unlikely(!(mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)))) {
2811             error("FREEBSD: getmntinfo() failed");
2812             do_space = 0;
2813             error("DISABLED: disk_space.* charts");
2814             do_inodes = 0;
2815             error("DISABLED: disk_inodes.* charts");
2816             error("DISABLED: getmntinfo module");
2817             return 1;
2818         } else {
2819             // Data to be stored in DICTIONARY mount_points.
2820             // This DICTIONARY is used to lookup the settings of the mount point on each iteration.
2821             struct mount_point_metadata {
2822                 int do_space;
2823                 int do_inodes;
2824
2825                 size_t collected; // the number of times this has been collected
2826
2827                 // charts and dimensions
2828
2829                 RRDSET *st_space;
2830                 RRDDIM *rd_space_used;
2831                 RRDDIM *rd_space_avail;
2832                 RRDDIM *rd_space_reserved;
2833
2834                 RRDSET *st_inodes;
2835                 RRDDIM *rd_inodes_used;
2836                 RRDDIM *rd_inodes_avail;
2837             };
2838             static DICTIONARY *mount_points = NULL;
2839             static SIMPLE_PATTERN *excluded_mountpoints = NULL;
2840             static SIMPLE_PATTERN *excluded_filesystems = NULL;
2841             int i;
2842
2843             if(unlikely(!mount_points)) {
2844
2845                 excluded_mountpoints = simple_pattern_create(
2846                         config_get(CONFIG_SECTION_GETMNTINFO, "exclude space metrics on paths",
2847                                    DELAULT_EXLUDED_PATHS),
2848                         SIMPLE_PATTERN_EXACT
2849                 );
2850
2851                 excluded_filesystems = simple_pattern_create(
2852                         config_get(CONFIG_SECTION_GETMNTINFO, "exclude space metrics on filesystems",
2853                                    DEFAULT_EXCLUDED_FILESYSTEMS),
2854                         SIMPLE_PATTERN_EXACT
2855                 );
2856
2857                 mount_points = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
2858             }
2859
2860             for (i = 0; i < mntsize; i++) {
2861
2862                 char title[4096 + 1];
2863                 int def_space, def_inodes, iter_space, iter_inodes;
2864
2865                 struct mount_point_metadata *m = dictionary_get(mount_points, mntbuf[i].f_mntonname);
2866                 if(unlikely(!m)) {
2867                     char var_name[4096 + 1];
2868                     snprintfz(var_name, 4096, "%s:%s", CONFIG_SECTION_GETMNTINFO, mntbuf[i].f_mntonname);
2869
2870                     def_space = do_space;
2871                     def_inodes = do_space;
2872
2873                     if(unlikely(simple_pattern_matches(excluded_mountpoints, mntbuf[i].f_mntonname))) {
2874                         def_space = CONFIG_BOOLEAN_NO;
2875                         def_inodes = CONFIG_BOOLEAN_NO;
2876                     }
2877
2878                     if(unlikely(simple_pattern_matches(excluded_filesystems, mntbuf[i].f_fstypename))) {
2879                         def_space = CONFIG_BOOLEAN_NO;
2880                         def_inodes = CONFIG_BOOLEAN_NO;
2881                     }
2882
2883                     iter_space  = config_get_boolean_ondemand(var_name, "space usage",  def_space);
2884                     iter_inodes = config_get_boolean_ondemand(var_name, "inodes usage", def_inodes);
2885
2886                     struct mount_point_metadata mp = {
2887                             .do_space = iter_space,
2888                             .do_inodes = iter_inodes,
2889
2890                             .collected = 0,
2891
2892                             .st_space = NULL,
2893                             .rd_space_avail = NULL,
2894                             .rd_space_used = NULL,
2895                             .rd_space_reserved = NULL,
2896
2897                             .st_inodes = NULL,
2898                             .rd_inodes_avail = NULL,
2899                             .rd_inodes_used = NULL,
2900                     };
2901
2902                     m = dictionary_set(mount_points, mntbuf[i].f_mntonname, &mp, sizeof(struct mount_point_metadata));
2903                 }
2904
2905                 if(unlikely(m->do_space == CONFIG_BOOLEAN_NO && m->do_inodes == CONFIG_BOOLEAN_NO))
2906                     continue;
2907
2908                 if(unlikely(mntbuf[i].f_flags & MNT_RDONLY && !m->collected))
2909                     continue;
2910
2911                 // --------------------------------------------------------------------------
2912
2913                 int rendered = 0;
2914
2915                 if (m->do_space == CONFIG_BOOLEAN_YES || (m->do_space == CONFIG_BOOLEAN_AUTO && (mntbuf[i].f_blocks > 2))) {
2916                     if (unlikely(!m->st_space)) {
2917                         snprintfz(title, 4096, "Disk Space Usage for %s [%s]",
2918                                   mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
2919                         m->st_space = rrdset_create_localhost("disk_space",
2920                                                               mntbuf[i].f_mntonname,
2921                                                               NULL,
2922                                                               mntbuf[i].f_mntonname,
2923                                                               "disk.space",
2924                                                               title,
2925                                                               "GB",
2926                                                               2023,
2927                                                               update_every,
2928                                                               RRDSET_TYPE_STACKED
2929                         );
2930
2931                         m->rd_space_avail    = rrddim_add(m->st_space, "avail", NULL,
2932                                                           mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
2933                         m->rd_space_used     = rrddim_add(m->st_space, "used", NULL,
2934                                                           mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
2935                         m->rd_space_reserved = rrddim_add(m->st_space, "reserved_for_root", "reserved for root",
2936                                                           mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
2937                     } else
2938                         rrdset_next(m->st_space);
2939
2940                     rrddim_set_by_pointer(m->st_space, m->rd_space_avail,    (collected_number) mntbuf[i].f_bavail);
2941                     rrddim_set_by_pointer(m->st_space, m->rd_space_used,     (collected_number) (mntbuf[i].f_blocks -
2942                                                                                                  mntbuf[i].f_bfree));
2943                     rrddim_set_by_pointer(m->st_space, m->rd_space_reserved, (collected_number) (mntbuf[i].f_bfree -
2944                                                                                                  mntbuf[i].f_bavail));
2945                     rrdset_done(m->st_space);
2946
2947                     rendered++;
2948                 }
2949
2950                 // --------------------------------------------------------------------------
2951
2952                 if (m->do_inodes == CONFIG_BOOLEAN_YES || (m->do_inodes == CONFIG_BOOLEAN_AUTO && (mntbuf[i].f_files > 1))) {
2953                     if (unlikely(!m->st_inodes)) {
2954                         snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]",
2955                                   mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
2956                         m->st_inodes = rrdset_create_localhost("disk_inodes",
2957                                                                mntbuf[i].f_mntonname,
2958                                                                NULL,
2959                                                                mntbuf[i].f_mntonname,
2960                                                                "disk.inodes",
2961                                                                title,
2962                                                                "Inodes",
2963                                                                2024,
2964                                                                update_every,
2965                                                                RRDSET_TYPE_STACKED
2966                         );
2967
2968                         m->rd_inodes_avail = rrddim_add(m->st_inodes, "avail", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2969                         m->rd_inodes_used  = rrddim_add(m->st_inodes, "used",  NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2970                     } else
2971                         rrdset_next(m->st_inodes);
2972
2973                     rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_avail, (collected_number) mntbuf[i].f_ffree);
2974                     rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_used,  (collected_number) (mntbuf[i].f_files -
2975                                                                                                 mntbuf[i].f_ffree));
2976                     rrdset_done(m->st_inodes);
2977
2978                     rendered++;
2979                 }
2980
2981                 if(likely(rendered))
2982                     m->collected++;
2983             }
2984         }
2985     } else {
2986         error("DISABLED: getmntinfo module");
2987         return 1;
2988     }
2989
2990     return 0;
2991 }
2992
2993 // --------------------------------------------------------------------------------------------------------------------
2994 // getifaddrs
2995
2996 int do_getifaddrs(int update_every, usec_t dt) {
2997     (void)dt;
2998
2999 #define DELAULT_EXLUDED_INTERFACES "lo*"
3000 #define CONFIG_SECTION_GETIFADDRS "plugin:freebsd:getifaddrs"
3001
3002     static int do_bandwidth_ipv4 = -1, do_bandwidth_ipv6 = -1, do_bandwidth = -1, do_packets = -1,
3003                do_errors = -1, do_drops = -1, do_events = -1;
3004
3005     if (unlikely(do_bandwidth_ipv4 == -1)) {
3006         do_bandwidth_ipv4 = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "total bandwidth for ipv4 interfaces",
3007                                                         CONFIG_BOOLEAN_AUTO);
3008         do_bandwidth_ipv6 = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "total bandwidth for ipv6 interfaces",
3009                                                         CONFIG_BOOLEAN_AUTO);
3010         do_bandwidth      = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "bandwidth for all interfaces",
3011                                                         CONFIG_BOOLEAN_AUTO);
3012         do_packets        = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "packets for all interfaces",
3013                                                         CONFIG_BOOLEAN_AUTO);
3014         do_errors         = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "errors for all interfaces",
3015                                                         CONFIG_BOOLEAN_AUTO);
3016         do_drops          = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "drops for all interfaces",
3017                                                         CONFIG_BOOLEAN_AUTO);
3018         do_events         = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "collisions for all interfaces",
3019                                                         CONFIG_BOOLEAN_AUTO);
3020     }
3021
3022     if (likely(do_bandwidth_ipv4 || do_bandwidth_ipv6 || do_bandwidth || do_packets || do_errors ||
3023                do_drops || do_events)) {
3024         struct ifaddrs *ifap;
3025
3026         if (unlikely(getifaddrs(&ifap))) {
3027             error("FREEBSD: getifaddrs() failed");
3028             do_bandwidth_ipv4 = 0;
3029             error("DISABLED: system.ipv4 chart");
3030             do_bandwidth_ipv6 = 0;
3031             error("DISABLED: system.ipv6 chart");
3032             do_bandwidth = 0;
3033             error("DISABLED: net.* charts");
3034             do_packets = 0;
3035             error("DISABLED: net_packets.* charts");
3036             do_errors = 0;
3037             error("DISABLED: net_errors.* charts");
3038             do_drops = 0;
3039             error("DISABLED: net_drops.* charts");
3040             do_events = 0;
3041             error("DISABLED: net_events.* charts");
3042             error("DISABLED: getifaddrs module");
3043             return 1;
3044         } else {
3045             #define IFA_DATA(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s)
3046             struct ifaddrs *ifa;
3047             struct iftot {
3048                 u_long  ift_ibytes;
3049                 u_long  ift_obytes;
3050             } iftot = {0, 0};
3051
3052             // --------------------------------------------------------------------
3053
3054             if (likely(do_bandwidth_ipv4)) {
3055                 iftot.ift_ibytes = iftot.ift_obytes = 0;
3056                 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
3057                     if (ifa->ifa_addr->sa_family != AF_INET)
3058                         continue;
3059                     iftot.ift_ibytes += IFA_DATA(ibytes);
3060                     iftot.ift_obytes += IFA_DATA(obytes);
3061                 }
3062
3063                 static RRDSET *st = NULL;
3064                 static RRDDIM *rd_in = NULL, *rd_out = NULL;
3065
3066                 if (unlikely(!st)) {
3067                     st = rrdset_create_localhost("system",
3068                                                  "ipv4",
3069                                                  NULL,
3070                                                  "network",
3071                                                  NULL,
3072                                                  "IPv4 Bandwidth",
3073                                                  "kilobits/s",
3074                                                  500,
3075                                                  update_every,
3076                                                  RRDSET_TYPE_AREA
3077                     );
3078
3079                     rd_in  = rrddim_add(st, "InOctets",  "received", 8, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
3080                     rd_out = rrddim_add(st, "OutOctets", "sent",    -8, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
3081                 } else
3082                     rrdset_next(st);
3083
3084                 rrddim_set_by_pointer(st, rd_in,  iftot.ift_ibytes);
3085                 rrddim_set_by_pointer(st, rd_out, iftot.ift_obytes);
3086                 rrdset_done(st);
3087             }
3088
3089             // --------------------------------------------------------------------
3090
3091             if (likely(do_bandwidth_ipv6)) {
3092                 iftot.ift_ibytes = iftot.ift_obytes = 0;
3093                 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
3094                     if (ifa->ifa_addr->sa_family != AF_INET6)
3095                         continue;
3096                     iftot.ift_ibytes += IFA_DATA(ibytes);
3097                     iftot.ift_obytes += IFA_DATA(obytes);
3098                 }
3099
3100                 static RRDSET *st = NULL;
3101                 static RRDDIM *rd_in = NULL, *rd_out = NULL;
3102
3103                 if (unlikely(!st)) {
3104                     st = rrdset_create_localhost("system",
3105                                                  "ipv6",
3106                                                  NULL,
3107                                                  "network",
3108                                                  NULL,
3109                                                  "IPv6 Bandwidth",
3110                                                  "kilobits/s",
3111                                                  500,
3112                                                  update_every,
3113                                                  RRDSET_TYPE_AREA
3114                     );
3115
3116                     rd_in  = rrddim_add(st, "received", NULL,  8, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
3117                     rd_out = rrddim_add(st, "sent",     NULL, -8, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
3118                 } else
3119                     rrdset_next(st);
3120
3121                 rrddim_set_by_pointer(st, rd_in,  iftot.ift_ibytes);
3122                 rrddim_set_by_pointer(st, rd_out, iftot.ift_obytes);
3123                 rrdset_done(st);
3124             }
3125
3126             // --------------------------------------------------------------------
3127
3128             // Data to be stored in DICTIONARY interfaces.
3129             // This DICTIONARY is used to lookup the settings of the interfaces on each iteration.
3130             struct interfaces_metadata {
3131                 int do_bandwidth;
3132                 int do_packets;
3133                 int do_errors;
3134                 int do_drops;
3135                 int do_events;
3136
3137                 // charts and dimensions
3138
3139                 RRDSET *st_bandwidth;
3140                 RRDDIM *rd_bandwidth_in;
3141                 RRDDIM *rd_bandwidth_out;
3142
3143                 RRDSET *st_packets;
3144                 RRDDIM *rd_packets_in;
3145                 RRDDIM *rd_packets_out;
3146                 RRDDIM *rd_packets_m_in;
3147                 RRDDIM *rd_packets_m_out;
3148
3149                 RRDSET *st_errors;
3150                 RRDDIM *rd_errors_in;
3151                 RRDDIM *rd_errors_out;
3152
3153                 RRDSET *st_drops;
3154                 RRDDIM *rd_drops_in;
3155                 RRDDIM *rd_drops_out;
3156
3157                 RRDSET *st_events;
3158                 RRDDIM *rd_events_coll;
3159             };
3160             static DICTIONARY *interfaces = NULL;
3161             static SIMPLE_PATTERN *excluded_interfaces = NULL;
3162
3163             if(unlikely(!interfaces)) {
3164
3165                 excluded_interfaces = simple_pattern_create(
3166                         config_get(CONFIG_SECTION_GETIFADDRS, "disable by default interfaces matching",
3167                                    DELAULT_EXLUDED_INTERFACES)
3168                         , SIMPLE_PATTERN_EXACT
3169                 );
3170
3171                 interfaces = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
3172             }
3173
3174             for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
3175                 if (ifa->ifa_addr->sa_family != AF_LINK)
3176                     continue;
3177
3178                 int def_bandwidth, def_packets, def_errors, def_drops, def_events,
3179                     iter_bandwidth, iter_packets, iter_errors, iter_drops, iter_events;
3180
3181                 struct interfaces_metadata *ifm = dictionary_get(interfaces, ifa->ifa_name);
3182                 if(unlikely(!ifm)) {
3183                     char var_name[4096 + 1];
3184                     snprintfz(var_name, 4096, "%s:%s", CONFIG_SECTION_GETIFADDRS, ifa->ifa_name);
3185
3186                     def_bandwidth = do_bandwidth;
3187                     def_packets   = do_packets;
3188                     def_errors    = do_errors;
3189                     def_drops     = do_drops;
3190                     def_events    = do_events;
3191
3192                     if(unlikely(simple_pattern_matches(excluded_interfaces, ifa->ifa_name))) {
3193                         def_bandwidth = CONFIG_BOOLEAN_NO;
3194                         def_packets   = CONFIG_BOOLEAN_NO;
3195                         def_errors    = CONFIG_BOOLEAN_NO;
3196                         def_drops     = CONFIG_BOOLEAN_NO;
3197                         def_events    = CONFIG_BOOLEAN_NO;
3198                     }
3199
3200                     iter_bandwidth = config_get_boolean_ondemand(var_name, "bandwidth", def_bandwidth);
3201                     iter_packets   = config_get_boolean_ondemand(var_name, "packets",   def_packets);
3202                     iter_errors    = config_get_boolean_ondemand(var_name, "errors",    def_errors);
3203                     iter_drops     = config_get_boolean_ondemand(var_name, "drops",     def_drops);
3204                     iter_events    = config_get_boolean_ondemand(var_name, "events",    def_events);
3205
3206                     struct interfaces_metadata ifmp = {
3207                             .do_bandwidth = iter_bandwidth,
3208                             .do_packets   = iter_packets,
3209                             .do_errors    = iter_errors,
3210                             .do_drops     = iter_drops,
3211                             .do_events    = iter_events,
3212
3213                             .st_bandwidth = NULL,
3214                             .rd_bandwidth_in = NULL,
3215                             .rd_bandwidth_out = NULL,
3216
3217                             .st_packets = NULL,
3218                             .rd_packets_in = NULL,
3219                             .rd_packets_out = NULL,
3220                             .rd_packets_m_in = NULL,
3221                             .rd_packets_m_out = NULL,
3222
3223                             .st_errors = NULL,
3224                             .rd_errors_in = NULL,
3225                             .rd_errors_out = NULL,
3226
3227                             .st_drops = NULL,
3228                             .rd_drops_in = NULL,
3229                             .rd_drops_out = NULL,
3230
3231                             .st_events = NULL,
3232                             .rd_events_coll = NULL,
3233                     };
3234
3235                     ifm = dictionary_set(interfaces, ifa->ifa_name, &ifmp, sizeof(struct interfaces_metadata));
3236                 }
3237
3238                 // --------------------------------------------------------------------
3239
3240                 if (ifm->do_bandwidth == CONFIG_BOOLEAN_YES || (ifm->do_bandwidth == CONFIG_BOOLEAN_AUTO &&
3241                         (IFA_DATA(ibytes) || IFA_DATA(obytes)))) {
3242                     if (unlikely(!ifm->st_bandwidth)) {
3243                         ifm->st_bandwidth = rrdset_create_localhost("net",
3244                                                                     ifa->ifa_name,
3245                                                                     NULL,
3246                                                                     ifa->ifa_name,
3247                                                                     "net.net",
3248                                                                     "Bandwidth",
3249                                                                     "kilobits/s",
3250                                                                     7000,
3251                                                                     update_every,
3252                                                                     RRDSET_TYPE_AREA
3253                         );
3254
3255                         ifm->rd_bandwidth_in  = rrddim_add(ifm->st_bandwidth, "received", NULL,  8, KILO_FACTOR,
3256                                                            RRD_ALGORITHM_INCREMENTAL);
3257                         ifm->rd_bandwidth_out = rrddim_add(ifm->st_bandwidth, "sent",     NULL, -8, KILO_FACTOR,
3258                                                            RRD_ALGORITHM_INCREMENTAL);
3259                     } else
3260                         rrdset_next(ifm->st_bandwidth);
3261
3262                     rrddim_set_by_pointer(ifm->st_bandwidth, ifm->rd_bandwidth_in,  IFA_DATA(ibytes));
3263                     rrddim_set_by_pointer(ifm->st_bandwidth, ifm->rd_bandwidth_out, IFA_DATA(obytes));
3264                     rrdset_done(ifm->st_bandwidth);
3265                 }
3266
3267                 // --------------------------------------------------------------------
3268
3269                 if (ifm->do_packets == CONFIG_BOOLEAN_YES || (ifm->do_packets == CONFIG_BOOLEAN_AUTO &&
3270                         (IFA_DATA(ipackets) || IFA_DATA(opackets) || IFA_DATA(imcasts) || IFA_DATA(omcasts)))) {
3271                     if (unlikely(!ifm->st_packets)) {
3272                         ifm->st_packets = rrdset_create_localhost("net_packets",
3273                                                                   ifa->ifa_name,
3274                                                                   NULL,
3275                                                                   ifa->ifa_name,
3276                                                                   "net.packets",
3277                                                                   "Packets",
3278                                                                   "packets/s",
3279                                                                   7001,
3280                                                                   update_every,
3281                                                                   RRDSET_TYPE_LINE
3282                         );
3283
3284                         rrdset_flag_set(ifm->st_packets, RRDSET_FLAG_DETAIL);
3285
3286                         ifm->rd_packets_in    = rrddim_add(ifm->st_packets, "received",           NULL,  1, 1,
3287                                                            RRD_ALGORITHM_INCREMENTAL);
3288                         ifm->rd_packets_out   = rrddim_add(ifm->st_packets, "sent",               NULL, -1, 1,
3289                                                            RRD_ALGORITHM_INCREMENTAL);
3290                         ifm->rd_packets_m_in  = rrddim_add(ifm->st_packets, "multicast_received", NULL,  1, 1,
3291                                                            RRD_ALGORITHM_INCREMENTAL);
3292                         ifm->rd_packets_m_out = rrddim_add(ifm->st_packets, "multicast_sent",     NULL, -1, 1,
3293                                                            RRD_ALGORITHM_INCREMENTAL);
3294                     } else
3295                         rrdset_next(ifm->st_packets);
3296
3297                     rrddim_set_by_pointer(ifm->st_packets, ifm->rd_packets_in,    IFA_DATA(ipackets));
3298                     rrddim_set_by_pointer(ifm->st_packets, ifm->rd_packets_out,   IFA_DATA(opackets));
3299                     rrddim_set_by_pointer(ifm->st_packets, ifm->rd_packets_m_in,  IFA_DATA(imcasts));
3300                     rrddim_set_by_pointer(ifm->st_packets, ifm->rd_packets_m_out, IFA_DATA(omcasts));
3301                     rrdset_done(ifm->st_packets);
3302                 }
3303
3304                 // --------------------------------------------------------------------
3305
3306                 if (ifm->do_errors == CONFIG_BOOLEAN_YES || (ifm->do_errors == CONFIG_BOOLEAN_AUTO &&
3307                         (IFA_DATA(ierrors) || IFA_DATA(oerrors)))) {
3308                     if (unlikely(!ifm->st_errors)) {
3309                         ifm->st_errors = rrdset_create_localhost("net_errors",
3310                                                                  ifa->ifa_name,
3311                                                                  NULL,
3312                                                                  ifa->ifa_name,
3313                                                                  "net.errors",
3314                                                                  "Interface Errors",
3315                                                                  "errors/s",
3316                                                                  7002,
3317                                                                  update_every,
3318                                                                  RRDSET_TYPE_LINE
3319                         );
3320
3321                         rrdset_flag_set(ifm->st_errors, RRDSET_FLAG_DETAIL);
3322
3323                         ifm->rd_errors_in  = rrddim_add(ifm->st_errors, "inbound",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
3324                         ifm->rd_errors_out = rrddim_add(ifm->st_errors, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
3325                     } else
3326                         rrdset_next(ifm->st_errors);
3327
3328                     rrddim_set_by_pointer(ifm->st_errors, ifm->rd_errors_in,  IFA_DATA(ierrors));
3329                     rrddim_set_by_pointer(ifm->st_errors, ifm->rd_errors_out, IFA_DATA(oerrors));
3330                     rrdset_done(ifm->st_errors);
3331                 }
3332                 // --------------------------------------------------------------------
3333
3334                 if (ifm->do_drops == CONFIG_BOOLEAN_YES || (ifm->do_drops == CONFIG_BOOLEAN_AUTO &&
3335                         (IFA_DATA(iqdrops)
3336 #if __FreeBSD__ >= 11
3337                          || IFA_DATA(oqdrops)
3338 #endif
3339                         ))) {
3340                     if (unlikely(!ifm->st_drops)) {
3341                         ifm->st_drops = rrdset_create_localhost("net_drops",
3342                                                                 ifa->ifa_name,
3343                                                                 NULL,
3344                                                                 ifa->ifa_name,
3345                                                                 "net.drops",
3346                                                                 "Interface Drops",
3347                                                                 "drops/s",
3348                                                                 7003,
3349                                                                 update_every,
3350                                                                 RRDSET_TYPE_LINE
3351                         );
3352
3353                         rrdset_flag_set(ifm->st_drops, RRDSET_FLAG_DETAIL);
3354
3355                         ifm->rd_drops_in  = rrddim_add(ifm->st_drops, "inbound",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
3356 #if __FreeBSD__ >= 11
3357                         ifm->rd_drops_out = rrddim_add(ifm->st_drops, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
3358 #endif
3359                     } else
3360                         rrdset_next(ifm->st_drops);
3361
3362                     rrddim_set_by_pointer(ifm->st_drops, ifm->rd_drops_in,  IFA_DATA(iqdrops));
3363 #if __FreeBSD__ >= 11
3364                     rrddim_set_by_pointer(ifm->st_drops, ifm->rd_drops_out, IFA_DATA(oqdrops));
3365 #endif
3366                     rrdset_done(ifm->st_drops);
3367                 }
3368
3369                 // --------------------------------------------------------------------
3370
3371                 if (ifm->do_events == CONFIG_BOOLEAN_YES || (ifm->do_events == CONFIG_BOOLEAN_AUTO &&
3372                                                              IFA_DATA(collisions))) {
3373                     if (unlikely(!ifm->st_events)) {
3374                         ifm->st_events = rrdset_create_localhost("net_events",
3375                                                                  ifa->ifa_name,
3376                                                                  NULL,
3377                                                                  ifa->ifa_name,
3378                                                                  "net.events",
3379                                                                  "Network Interface Events",
3380                                                                  "events/s",
3381                                                                  7006,
3382                                                                  update_every,
3383                                                                  RRDSET_TYPE_LINE
3384                         );
3385
3386                         rrdset_flag_set(ifm->st_events, RRDSET_FLAG_DETAIL);
3387
3388                         ifm->rd_events_coll = rrddim_add(ifm->st_events, "collisions", NULL, -1, 1,
3389                                                          RRD_ALGORITHM_INCREMENTAL);
3390                     } else
3391                         rrdset_next(ifm->st_events);
3392
3393                     rrddim_set_by_pointer(ifm->st_events, ifm->rd_events_coll, IFA_DATA(collisions));
3394                     rrdset_done(ifm->st_events);
3395                 }
3396             }
3397
3398             freeifaddrs(ifap);
3399         }
3400     } else {
3401         error("DISABLED: getifaddrs module");
3402         return 1;
3403     }
3404
3405     return 0;
3406 }
3407
3408 // --------------------------------------------------------------------------------------------------------------------
3409 // kern.devstat
3410
3411 int do_kern_devstat(int update_every, usec_t dt) {
3412
3413 #define DELAULT_EXLUDED_DISKS ""
3414 #define CONFIG_SECTION_KERN_DEVSTAT "plugin:freebsd:kern.devstat"
3415 #define BINTIME_SCALE 5.42101086242752217003726400434970855712890625e-17 // this is 1000/2^64
3416
3417     static int enable_pass_devices = -1, do_system_io = -1, do_io = -1, do_ops = -1, do_qops = -1, do_util = -1,
3418                do_iotime = -1, do_await = -1, do_avagsz = -1, do_svctm = -1;
3419
3420     if (unlikely(enable_pass_devices == -1)) {
3421         enable_pass_devices = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT,
3422                                                           "performance metrics for pass devices", CONFIG_BOOLEAN_AUTO);
3423
3424         do_system_io = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "total bandwidth for all disks",
3425                                                    CONFIG_BOOLEAN_YES);
3426
3427         do_io     = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "bandwidth for all disks",
3428                                                 CONFIG_BOOLEAN_AUTO);
3429         do_ops    = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "operations for all disks",
3430                                                 CONFIG_BOOLEAN_AUTO);
3431         do_qops   = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "queued operations for all disks",
3432                                                 CONFIG_BOOLEAN_AUTO);
3433         do_util   = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "utilization percentage for all disks",
3434                                                 CONFIG_BOOLEAN_AUTO);
3435         do_iotime = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "i/o time for all disks",
3436                                                 CONFIG_BOOLEAN_AUTO);
3437         do_await  = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "average completed i/o time for all disks",
3438                                                 CONFIG_BOOLEAN_AUTO);
3439         do_avagsz = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "average completed i/o bandwidth for all disks",
3440                                                 CONFIG_BOOLEAN_AUTO);
3441         do_svctm  = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "average service time for all disks",
3442                                                 CONFIG_BOOLEAN_AUTO);
3443     }
3444
3445     if (likely(do_system_io || do_io || do_ops || do_qops || do_util || do_iotime || do_await || do_avagsz || do_svctm)) {
3446         static int mib_numdevs[3] = {0, 0, 0};
3447         int numdevs;
3448         int common_error = 0;
3449
3450         if (unlikely(GETSYSCTL_SIMPLE("kern.devstat.numdevs", mib_numdevs, numdevs))) {
3451             common_error = 1;
3452         } else {
3453             static int mib_devstat[3] = {0, 0, 0};
3454             static void *devstat_data = NULL;
3455             static int old_numdevs = 0;
3456
3457             if (unlikely(numdevs != old_numdevs)) {
3458                 devstat_data = reallocz(devstat_data, sizeof(long) + sizeof(struct devstat) *
3459                                         numdevs); // there is generation number before devstat structures
3460                 old_numdevs = numdevs;
3461             }
3462             if (unlikely(GETSYSCTL_WSIZE("kern.devstat.all", mib_devstat, devstat_data,
3463                                          sizeof(long) + sizeof(struct devstat) * numdevs))) {
3464                 common_error = 1;
3465             } else {
3466                 struct devstat *dstat;
3467                 int i;
3468                 collected_number total_disk_kbytes_read = 0;
3469                 collected_number total_disk_kbytes_write = 0;
3470
3471                 // Data to be stored in DICTIONARY disks.
3472                 // This DICTIONARY is used to lookup the settings of the disks on each iteration.
3473                 struct disks_metadata {
3474                     int do_io;
3475                     int do_ops;
3476                     int do_qops;
3477                     int do_util;
3478                     int do_iotime;
3479                     int do_await;
3480                     int do_avagsz;
3481                     int do_svctm;
3482
3483
3484                     // data for differential charts
3485
3486                     struct prev_dstat {
3487                         collected_number bytes_read;
3488                         collected_number bytes_write;
3489                         collected_number operations_read;
3490                         collected_number operations_write;
3491                         collected_number duration_read_ms;
3492                         collected_number duration_write_ms;
3493                         collected_number busy_time_ms;
3494                     } prev_dstat;
3495
3496                     // charts and dimensions
3497
3498                     RRDSET *st_io;
3499                     RRDDIM *rd_io_in;
3500                     RRDDIM *rd_io_out;
3501
3502                     RRDSET *st_ops;
3503                     RRDDIM *rd_ops_in;
3504                     RRDDIM *rd_ops_out;
3505
3506                     RRDSET *st_qops;
3507                     RRDDIM *rd_qops;
3508
3509                     RRDSET *st_util;
3510                     RRDDIM *rd_util;
3511
3512                     RRDSET *st_iotime;
3513                     RRDDIM *rd_iotime_in;
3514                     RRDDIM *rd_iotime_out;
3515
3516                     RRDSET *st_await;
3517                     RRDDIM *rd_await_in;
3518                     RRDDIM *rd_await_out;
3519
3520                     RRDSET *st_avagsz;
3521                     RRDDIM *rd_avagsz_in;
3522                     RRDDIM *rd_avagsz_out;
3523
3524                     RRDSET *st_svctm;
3525                     RRDDIM *rd_svctm;
3526
3527                 };
3528                 static DICTIONARY *disks = NULL;
3529                 static SIMPLE_PATTERN *excluded_disks = NULL;
3530
3531                 if(unlikely(!disks)) {
3532
3533                     excluded_disks = simple_pattern_create(
3534                             config_get(CONFIG_SECTION_KERN_DEVSTAT, "disable by default disks matching",
3535                                        DELAULT_EXLUDED_DISKS)
3536                             , SIMPLE_PATTERN_EXACT
3537                     );
3538
3539                     disks = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
3540                 }
3541
3542                 dstat = devstat_data + sizeof(long); // skip generation number
3543
3544                 for (i = 0; i < numdevs; i++) {
3545                     if (likely(do_system_io)) {
3546                         if (((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) || ((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) {
3547                             total_disk_kbytes_read += dstat[i].bytes[DEVSTAT_READ] / KILO_FACTOR;
3548                             total_disk_kbytes_write += dstat[i].bytes[DEVSTAT_WRITE] / KILO_FACTOR;
3549                         }
3550                     }
3551
3552                     if (unlikely(!enable_pass_devices))
3553                         if ((dstat[i].device_type & DEVSTAT_TYPE_PASS) == DEVSTAT_TYPE_PASS)
3554                             continue;
3555
3556                     if (((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) || ((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) {
3557                         char disk[DEVSTAT_NAME_LEN + MAX_INT_DIGITS + 1];
3558                         int def_io, def_ops, def_qops, def_util, def_iotime, def_await, def_avagsz, def_svctm,
3559                             iter_io, iter_ops, iter_qops, iter_util, iter_iotime, iter_await, iter_avagsz, iter_svctm;
3560                         struct cur_dstat {
3561                             collected_number duration_read_ms;
3562                             collected_number duration_write_ms;
3563                             collected_number busy_time_ms;
3564                         } cur_dstat;
3565
3566                         sprintf(disk, "%s%d", dstat[i].device_name, dstat[i].unit_number);
3567
3568                         struct disks_metadata *dm = dictionary_get(disks, disk);
3569                         if(unlikely(!dm)) {
3570                             char var_name[4096 + 1];
3571                             snprintfz(var_name, 4096, "%s:%s", CONFIG_SECTION_KERN_DEVSTAT, disk);
3572
3573                             def_io     = do_io;
3574                             def_ops    = do_ops;
3575                             def_qops   = do_qops;
3576                             def_util   = do_util;
3577                             def_iotime = do_iotime;
3578                             def_await  = do_await;
3579                             def_avagsz = do_avagsz;
3580                             def_svctm  = do_svctm;
3581
3582                             if(unlikely(simple_pattern_matches(excluded_disks, disk))) {
3583                                 def_io     = CONFIG_BOOLEAN_NO;
3584                                 def_ops    = CONFIG_BOOLEAN_NO;
3585                                 def_qops   = CONFIG_BOOLEAN_NO;
3586                                 def_util   = CONFIG_BOOLEAN_NO;
3587                                 def_iotime = CONFIG_BOOLEAN_NO;
3588                                 def_await  = CONFIG_BOOLEAN_NO;
3589                                 def_avagsz = CONFIG_BOOLEAN_NO;
3590                                 def_svctm  = CONFIG_BOOLEAN_NO;
3591                             }
3592
3593                             iter_io     = config_get_boolean_ondemand(var_name, "bandwidth",                  def_io);
3594                             iter_ops    = config_get_boolean_ondemand(var_name, "operations",                 def_ops);
3595                             iter_qops   = config_get_boolean_ondemand(var_name, "queued operations",          def_qops);
3596                             iter_util   = config_get_boolean_ondemand(var_name, "utilization percentage",     def_util);
3597                             iter_iotime = config_get_boolean_ondemand(var_name, "i/o time",                   def_iotime);
3598                             iter_await  = config_get_boolean_ondemand(var_name, "average completed i/o time", def_await);
3599                             iter_avagsz = config_get_boolean_ondemand(var_name, "average completed i/o bandwidth",
3600                                                                                                               def_avagsz);
3601                             iter_svctm  = config_get_boolean_ondemand(var_name, "average service time",       def_svctm);
3602
3603                             struct disks_metadata dmp = {
3604                                     .do_io     = iter_io,
3605                                     .do_ops    = iter_ops,
3606                                     .do_qops   = iter_qops,
3607                                     .do_util   = iter_util,
3608                                     .do_iotime = iter_iotime,
3609                                     .do_await  = iter_await,
3610                                     .do_avagsz = iter_avagsz,
3611                                     .do_svctm  = iter_svctm,
3612
3613                                     .st_io = NULL,
3614                                     .rd_io_in = NULL,
3615                                     .rd_io_out = NULL,
3616
3617                                     .st_ops = NULL,
3618                                     .rd_ops_in = NULL,
3619                                     .rd_ops_out = NULL,
3620
3621                                     .st_qops = NULL,
3622                                     .rd_qops = NULL,
3623
3624                                     .st_util = NULL,
3625                                     .rd_util = NULL,
3626
3627                                     .st_iotime = NULL,
3628                                     .rd_iotime_in = NULL,
3629                                     .rd_iotime_out = NULL,
3630
3631                                     .st_await = NULL,
3632                                     .rd_await_in = NULL,
3633                                     .rd_await_out = NULL,
3634
3635                                     .st_avagsz = NULL,
3636                                     .rd_avagsz_in = NULL,
3637                                     .rd_avagsz_out = NULL,
3638
3639                                     .st_svctm = NULL,
3640                                     .rd_svctm = NULL,
3641                             };
3642
3643                             // initialise data for differential charts
3644
3645                             dmp.prev_dstat.bytes_read        = dstat[i].bytes[DEVSTAT_READ];
3646                             dmp.prev_dstat.bytes_write       = dstat[i].bytes[DEVSTAT_WRITE];
3647                             dmp.prev_dstat.operations_read   = dstat[i].operations[DEVSTAT_READ];
3648                             dmp.prev_dstat.operations_write  = dstat[i].operations[DEVSTAT_WRITE];
3649                             dmp.prev_dstat.duration_read_ms  = dstat[i].duration[DEVSTAT_READ].sec * 1000
3650                                                                + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
3651                             dmp.prev_dstat.duration_write_ms = dstat[i].duration[DEVSTAT_WRITE].sec * 1000
3652                                                                + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
3653                             dmp.prev_dstat.busy_time_ms      = dstat[i].busy_time.sec * 1000
3654                                                                + dstat[i].busy_time.frac * BINTIME_SCALE;
3655
3656                             dm = dictionary_set(disks, disk, &dmp, sizeof(struct disks_metadata));
3657                         }
3658
3659                         cur_dstat.duration_read_ms  = dstat[i].duration[DEVSTAT_READ].sec * 1000
3660                                                       + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
3661                         cur_dstat.duration_write_ms = dstat[i].duration[DEVSTAT_WRITE].sec * 1000
3662                                                       + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
3663                         cur_dstat.busy_time_ms = dstat[i].busy_time.sec * 1000 + dstat[i].busy_time.frac * BINTIME_SCALE;
3664
3665                         // --------------------------------------------------------------------
3666
3667                         if(dm->do_io == CONFIG_BOOLEAN_YES || (dm->do_io == CONFIG_BOOLEAN_AUTO &&
3668                                 (dstat[i].bytes[DEVSTAT_READ] || dstat[i].bytes[DEVSTAT_WRITE]))) {
3669                             if (unlikely(!dm->st_io)) {
3670                                 dm->st_io = rrdset_create_localhost("disk",
3671                                                                     disk,
3672                                                                     NULL,
3673                                                                     disk,
3674                                                                     "disk.io",
3675                                                                     "Disk I/O Bandwidth",
3676                                                                     "kilobytes/s",
3677                                                                     2000,
3678                                                                     update_every,
3679                                                                     RRDSET_TYPE_AREA
3680                                 );
3681
3682                                 dm->rd_io_in  = rrddim_add(dm->st_io, "reads",  NULL,  1, KILO_FACTOR,
3683                                                           RRD_ALGORITHM_INCREMENTAL);
3684                                 dm->rd_io_out = rrddim_add(dm->st_io, "writes", NULL, -1, KILO_FACTOR,
3685                                                            RRD_ALGORITHM_INCREMENTAL);
3686                             } else
3687                                 rrdset_next(dm->st_io);
3688
3689                             rrddim_set_by_pointer(dm->st_io, dm->rd_io_in,  dstat[i].bytes[DEVSTAT_READ]);
3690                             rrddim_set_by_pointer(dm->st_io, dm->rd_io_out, dstat[i].bytes[DEVSTAT_WRITE]);
3691                             rrdset_done(dm->st_io);
3692                         }
3693
3694                         // --------------------------------------------------------------------
3695
3696                         if(dm->do_ops == CONFIG_BOOLEAN_YES || (dm->do_ops == CONFIG_BOOLEAN_AUTO &&
3697                                 (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) {
3698                             if (unlikely(!dm->st_ops)) {
3699                                 dm->st_ops = rrdset_create_localhost("disk_ops",
3700                                                                      disk,
3701                                                                      NULL,
3702                                                                      disk,
3703                                                                      "disk.ops",
3704                                                                      "Disk Completed I/O Operations",
3705                                                                      "operations/s",
3706                                                                      2001,
3707                                                                      update_every,
3708                                                                      RRDSET_TYPE_LINE
3709                                 );
3710
3711                                 rrdset_flag_set(dm->st_ops, RRDSET_FLAG_DETAIL);
3712
3713                                 dm->rd_ops_in = rrddim_add(dm->st_ops, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
3714                                 dm->rd_ops_out = rrddim_add(dm->st_ops, "writes", NULL, -1, 1,
3715                                                             RRD_ALGORITHM_INCREMENTAL);
3716                             } else
3717                                 rrdset_next(dm->st_ops);
3718
3719                             rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_in, dstat[i].operations[DEVSTAT_READ]);
3720                             rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_out, dstat[i].operations[DEVSTAT_WRITE]);
3721                             rrdset_done(dm->st_ops);
3722                         }
3723
3724                         // --------------------------------------------------------------------
3725
3726                         if(dm->do_qops == CONFIG_BOOLEAN_YES || (dm->do_qops == CONFIG_BOOLEAN_AUTO &&
3727                                 (dstat[i].start_count || dstat[i].end_count))) {
3728                             if (unlikely(!dm->st_qops)) {
3729                                 dm->st_qops = rrdset_create_localhost("disk_qops",
3730                                                                       disk,
3731                                                                       NULL,
3732                                                                       disk,
3733                                                                       "disk.qops",
3734                                                                       "Disk Current I/O Operations",
3735                                                                       "operations",
3736                                                                       2002,
3737                                                                       update_every,
3738                                                                       RRDSET_TYPE_LINE
3739                                 );
3740
3741                                 rrdset_flag_set(dm->st_qops, RRDSET_FLAG_DETAIL);
3742
3743                                 dm->rd_qops = rrddim_add(dm->st_qops, "operations", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
3744                             } else
3745                                 rrdset_next(dm->st_qops);
3746
3747                             rrddim_set_by_pointer(dm->st_qops, dm->rd_qops, dstat[i].start_count - dstat[i].end_count);
3748                             rrdset_done(dm->st_qops);
3749                         }
3750
3751                         // --------------------------------------------------------------------
3752
3753                         if(dm->do_util == CONFIG_BOOLEAN_YES || (dm->do_util == CONFIG_BOOLEAN_AUTO &&
3754                                                                  cur_dstat.busy_time_ms)) {
3755                             if (unlikely(!dm->st_util)) {
3756                                 dm->st_util = rrdset_create_localhost("disk_util",
3757                                                                       disk,
3758                                                                       NULL,
3759                                                                       disk,
3760                                                                       "disk.util",
3761                                                                       "Disk Utilization Time",
3762                                                                       "% of time working",
3763                                                                       2004,
3764                                                                       update_every,
3765                                                                       RRDSET_TYPE_AREA
3766                                 );
3767
3768                                 rrdset_flag_set(dm->st_util, RRDSET_FLAG_DETAIL);
3769
3770                                 dm->rd_util = rrddim_add(dm->st_util, "utilization", NULL, 1, 10,
3771                                                          RRD_ALGORITHM_INCREMENTAL);
3772                             } else
3773                                 rrdset_next(dm->st_util);
3774
3775                             rrddim_set_by_pointer(dm->st_util, dm->rd_util, cur_dstat.busy_time_ms);
3776                             rrdset_done(dm->st_util);
3777                         }
3778
3779                         // --------------------------------------------------------------------
3780
3781                         if(dm->do_iotime == CONFIG_BOOLEAN_YES || (dm->do_iotime == CONFIG_BOOLEAN_AUTO &&
3782                                 (cur_dstat.duration_read_ms || cur_dstat.duration_write_ms))) {
3783                             if (unlikely(!dm->st_iotime)) {
3784                                 dm->st_iotime = rrdset_create_localhost("disk_iotime",
3785                                                                         disk,
3786                                                                         NULL,
3787                                                                         disk,
3788                                                                         "disk.iotime",
3789                                                                         "Disk Total I/O Time",
3790                                                                         "milliseconds/s",
3791                                                                         2022,
3792                                                                         update_every,
3793                                                                         RRDSET_TYPE_LINE
3794                                 );
3795
3796                                 rrdset_flag_set(dm->st_iotime, RRDSET_FLAG_DETAIL);
3797
3798                                 dm->rd_iotime_in  = rrddim_add(dm->st_iotime, "reads",  NULL,  1, 1,
3799                                                                RRD_ALGORITHM_INCREMENTAL);
3800                                 dm->rd_iotime_out = rrddim_add(dm->st_iotime, "writes", NULL, -1, 1,
3801                                                                RRD_ALGORITHM_INCREMENTAL);
3802                             } else
3803                                 rrdset_next(dm->st_iotime);
3804
3805                             rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_in,  cur_dstat.duration_read_ms);
3806                             rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_out, cur_dstat.duration_write_ms);
3807                             rrdset_done(dm->st_iotime);
3808                         }
3809
3810                         // --------------------------------------------------------------------
3811                         // calculate differential charts
3812                         // only if this is not the first time we run
3813
3814                         if (likely(dt)) {
3815
3816                             // --------------------------------------------------------------------
3817
3818                             if(dm->do_await == CONFIG_BOOLEAN_YES || (dm->do_await == CONFIG_BOOLEAN_AUTO &&
3819                                     (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) {
3820                                 if (unlikely(!dm->st_await)) {
3821                                     dm->st_await = rrdset_create_localhost("disk_await",
3822                                                                            disk,
3823                                                                            NULL,
3824                                                                            disk,
3825                                                                            "disk.await",
3826                                                                            "Average Completed I/O Operation Time",
3827                                                                            "ms per operation",
3828                                                                            2005,
3829                                                                            update_every,
3830                                                                            RRDSET_TYPE_LINE
3831                                     );
3832
3833                                     rrdset_flag_set(dm->st_await, RRDSET_FLAG_DETAIL);
3834
3835                                     dm->rd_await_in  = rrddim_add(dm->st_await, "reads",  NULL,  1, 1,
3836                                                                   RRD_ALGORITHM_ABSOLUTE);
3837                                     dm->rd_await_out = rrddim_add(dm->st_await, "writes", NULL, -1, 1,
3838                                                                   RRD_ALGORITHM_ABSOLUTE);
3839                                 } else
3840                                     rrdset_next(dm->st_await);
3841
3842                                 rrddim_set_by_pointer(dm->st_await, dm->rd_await_in,
3843                                                       (dstat[i].operations[DEVSTAT_READ] -
3844                                                        dm->prev_dstat.operations_read) ?
3845                                                       (cur_dstat.duration_read_ms - dm->prev_dstat.duration_read_ms) /
3846                                                       (dstat[i].operations[DEVSTAT_READ] -
3847                                                        dm->prev_dstat.operations_read) :
3848                                                       0);
3849                                 rrddim_set_by_pointer(dm->st_await, dm->rd_await_out,
3850                                                       (dstat[i].operations[DEVSTAT_WRITE] -
3851                                                        dm->prev_dstat.operations_write) ?
3852                                                       (cur_dstat.duration_write_ms - dm->prev_dstat.duration_write_ms) /
3853                                                       (dstat[i].operations[DEVSTAT_WRITE] -
3854                                                        dm->prev_dstat.operations_write) :
3855                                                       0);
3856                                 rrdset_done(dm->st_await);
3857                             }
3858
3859                             // --------------------------------------------------------------------
3860
3861                             if(dm->do_avagsz == CONFIG_BOOLEAN_YES || (dm->do_avagsz == CONFIG_BOOLEAN_AUTO &&
3862                                     (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) {
3863                                 if (unlikely(!dm->st_avagsz)) {
3864                                     dm->st_avagsz = rrdset_create_localhost("disk_avgsz",
3865                                                                             disk,
3866                                                                             NULL,
3867                                                                             disk,
3868                                                                             "disk.avgsz",
3869                                                                             "Average Completed I/O Operation Bandwidth",
3870                                                                             "kilobytes per operation",
3871                                                                             2006,
3872                                                                             update_every,
3873                                                                             RRDSET_TYPE_AREA
3874                                     );
3875
3876                                     rrdset_flag_set(dm->st_avagsz, RRDSET_FLAG_DETAIL);
3877
3878                                     dm->rd_avagsz_in  = rrddim_add(dm->st_avagsz, "reads",  NULL,  1, KILO_FACTOR,
3879                                                                   RRD_ALGORITHM_ABSOLUTE);
3880                                     dm->rd_avagsz_out = rrddim_add(dm->st_avagsz, "writes", NULL, -1, KILO_FACTOR,
3881                                                                    RRD_ALGORITHM_ABSOLUTE);
3882                                 } else
3883                                     rrdset_next(dm->st_avagsz);
3884
3885                                 rrddim_set_by_pointer(dm->st_avagsz, dm->rd_avagsz_in,
3886                                                       (dstat[i].operations[DEVSTAT_READ] -
3887                                                        dm->prev_dstat.operations_read) ?
3888                                                       (dstat[i].bytes[DEVSTAT_READ] - dm->prev_dstat.bytes_read) /
3889                                                       (dstat[i].operations[DEVSTAT_READ] -
3890                                                        dm->prev_dstat.operations_read) :
3891                                                       0);
3892                                 rrddim_set_by_pointer(dm->st_avagsz, dm->rd_avagsz_out,
3893                                                       (dstat[i].operations[DEVSTAT_WRITE] -
3894                                                        dm->prev_dstat.operations_write) ?
3895                                                       (dstat[i].bytes[DEVSTAT_WRITE] - dm->prev_dstat.bytes_write) /
3896                                                       (dstat[i].operations[DEVSTAT_WRITE] -
3897                                                        dm->prev_dstat.operations_write) :
3898                                                       0);
3899                                 rrdset_done(dm->st_avagsz);
3900                             }
3901
3902                             // --------------------------------------------------------------------
3903
3904                             if(dm->do_svctm == CONFIG_BOOLEAN_YES || (dm->do_svctm == CONFIG_BOOLEAN_AUTO &&
3905                                     (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) {
3906                                 if (unlikely(!dm->st_svctm)) {
3907                                     dm->st_svctm = rrdset_create_localhost("disk_svctm",
3908                                                                            disk,
3909                                                                            NULL,
3910                                                                            disk,
3911                                                                            "disk.svctm",
3912                                                                            "Average Service Time",
3913                                                                            "ms per operation",
3914                                                                            2007,
3915                                                                            update_every,
3916                                                                            RRDSET_TYPE_LINE
3917                                     );
3918
3919                                     rrdset_flag_set(dm->st_svctm, RRDSET_FLAG_DETAIL);
3920
3921                                     dm->rd_svctm = rrddim_add(dm->st_svctm, "svctm", NULL, 1, 1,
3922                                                               RRD_ALGORITHM_ABSOLUTE);
3923                                 } else
3924                                     rrdset_next(dm->st_svctm);
3925
3926                                 rrddim_set_by_pointer(dm->st_svctm, dm->rd_svctm,
3927                                     ((dstat[i].operations[DEVSTAT_READ] - dm->prev_dstat.operations_read) +
3928                                      (dstat[i].operations[DEVSTAT_WRITE] - dm->prev_dstat.operations_write)) ?
3929                                     (cur_dstat.busy_time_ms - dm->prev_dstat.busy_time_ms) /
3930                                     ((dstat[i].operations[DEVSTAT_READ] - dm->prev_dstat.operations_read) +
3931                                      (dstat[i].operations[DEVSTAT_WRITE] - dm->prev_dstat.operations_write)) :
3932                                     0);
3933                                 rrdset_done(dm->st_svctm);
3934                             }
3935
3936                             // --------------------------------------------------------------------
3937
3938                             dm->prev_dstat.bytes_read        = dstat[i].bytes[DEVSTAT_READ];
3939                             dm->prev_dstat.bytes_write       = dstat[i].bytes[DEVSTAT_WRITE];
3940                             dm->prev_dstat.operations_read   = dstat[i].operations[DEVSTAT_READ];
3941                             dm->prev_dstat.operations_write  = dstat[i].operations[DEVSTAT_WRITE];
3942                             dm->prev_dstat.duration_read_ms  = cur_dstat.duration_read_ms;
3943                             dm->prev_dstat.duration_write_ms = cur_dstat.duration_write_ms;
3944                             dm->prev_dstat.busy_time_ms      = cur_dstat.busy_time_ms;
3945                         }
3946                     }
3947                 }
3948
3949                 // --------------------------------------------------------------------
3950
3951                 if (likely(do_system_io)) {
3952                     static RRDSET *st = NULL;
3953                     static RRDDIM *rd_in = NULL, *rd_out = NULL;
3954
3955                     if (unlikely(!st)) {
3956                         st = rrdset_create_localhost("system",
3957                                                      "io",
3958                                                      NULL,
3959                                                      "disk",
3960                                                      NULL,
3961                                                      "Disk I/O",
3962                                                      "kilobytes/s",
3963                                                      150,
3964                                                      update_every,
3965                                                      RRDSET_TYPE_AREA
3966                         );
3967
3968                         rd_in  = rrddim_add(st, "in",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
3969                         rd_out = rrddim_add(st, "out", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
3970                     } else
3971                         rrdset_next(st);
3972
3973                     rrddim_set_by_pointer(st, rd_in,  total_disk_kbytes_read);
3974                     rrddim_set_by_pointer(st, rd_out, total_disk_kbytes_write);
3975                     rrdset_done(st);
3976                 }
3977             }
3978         }
3979         if (unlikely(common_error)) {
3980             do_system_io = 0;
3981             error("DISABLED: system.io chart");
3982             do_io = 0;
3983             error("DISABLED: disk.* charts");
3984             do_ops = 0;
3985             error("DISABLED: disk_ops.* charts");
3986             do_qops = 0;
3987             error("DISABLED: disk_qops.* charts");
3988             do_util = 0;
3989             error("DISABLED: disk_util.* charts");
3990             do_iotime = 0;
3991             error("DISABLED: disk_iotime.* charts");
3992             do_await = 0;
3993             error("DISABLED: disk_await.* charts");
3994             do_avagsz = 0;
3995             error("DISABLED: disk_avgsz.* charts");
3996             do_svctm = 0;
3997             error("DISABLED: disk_svctm.* charts");
3998             error("DISABLED: kern.devstat module");
3999             return 1;
4000         }
4001     } else {
4002         error("DISABLED: kern.devstat module");
4003         return 1;
4004     }
4005
4006     return 0;
4007 }