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