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