]> arthur.barton.de Git - netdata.git/blob - src/macos_fw.c
Merge pull request #1998 from ktsaou/master
[netdata.git] / src / macos_fw.c
1 #include "common.h"
2 #include <CoreFoundation/CoreFoundation.h>
3 #include <IOKit/IOKitLib.h>
4 #include <IOKit/storage/IOBlockStorageDriver.h>
5 #include <IOKit/IOBSD.h>
6 // NEEDED BY do_space, do_inodes
7 #include <sys/mount.h>
8 // NEEDED BY: struct ifaddrs, getifaddrs()
9 #include <net/if.h>
10 #include <ifaddrs.h>
11
12 // NEEDED BY: do_bandwidth
13 #define IFA_DATA(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s)
14
15 #define MAXDRIVENAME 31
16
17 #define KILO_FACTOR 1024
18 #define MEGA_FACTOR 1048576     // 1024 * 1024
19 #define GIGA_FACTOR 1073741824  // 1024 * 1024 * 1024
20
21 int do_macos_iokit(int update_every, usec_t dt) {
22     (void)dt;
23
24     static int do_io = -1, do_space = -1, do_inodes = -1, do_bandwidth = -1;
25
26     if (unlikely(do_io == -1)) {
27         do_io                   = config_get_boolean("plugin:macos:iokit", "disk i/o", 1);
28         do_space                = config_get_boolean("plugin:macos:sysctl", "space usage for all disks", 1);
29         do_inodes               = config_get_boolean("plugin:macos:sysctl", "inodes usage for all disks", 1);
30         do_bandwidth            = config_get_boolean("plugin:macos:sysctl", "bandwidth", 1);
31     }
32
33     RRDSET *st;
34
35     mach_port_t         master_port;
36     io_registry_entry_t drive, drive_media;
37     io_iterator_t       drive_list;
38     CFDictionaryRef     properties, statistics;
39     CFStringRef         name;
40     CFNumberRef         number;
41     kern_return_t       status;
42     collected_number    total_disk_reads = 0;
43     collected_number    total_disk_writes = 0;
44     struct diskstat {
45         char name[MAXDRIVENAME];
46         collected_number bytes_read;
47         collected_number bytes_write;
48         collected_number reads;
49         collected_number writes;
50         collected_number time_read;
51         collected_number time_write;
52         collected_number latency_read;
53         collected_number latency_write;
54     } diskstat;
55     struct cur_diskstat {
56         collected_number duration_read_ns;
57         collected_number duration_write_ns;
58         collected_number busy_time_ns;
59     } cur_diskstat;
60     struct prev_diskstat {
61         collected_number bytes_read;
62         collected_number bytes_write;
63         collected_number operations_read;
64         collected_number operations_write;
65         collected_number duration_read_ns;
66         collected_number duration_write_ns;
67         collected_number busy_time_ns;
68     } prev_diskstat;
69
70     // NEEDED BY: do_space, do_inodes
71     struct statfs *mntbuf;
72     int mntsize, i;
73     char mntonname[MNAMELEN + 1];
74     char title[4096 + 1];
75
76     // NEEDED BY: do_bandwidth
77     struct ifaddrs *ifa, *ifap;
78
79     /* Get ports and services for drive statistics. */
80     if (unlikely(IOMasterPort(bootstrap_port, &master_port))) {
81         error("MACOS: IOMasterPort() failed");
82         do_io = 0;
83         error("DISABLED: system.io");
84     /* Get the list of all drive objects. */
85     } else if (unlikely(IOServiceGetMatchingServices(master_port, IOServiceMatching("IOBlockStorageDriver"), &drive_list))) {
86         error("MACOS: IOServiceGetMatchingServices() failed");
87         do_io = 0;
88         error("DISABLED: system.io");
89     } else {
90         while ((drive = IOIteratorNext(drive_list)) != 0) {
91             properties = 0;
92             statistics = 0;
93             number = 0;
94             bzero(&diskstat, sizeof(diskstat));
95
96             /* Get drive media object. */
97             status = IORegistryEntryGetChildEntry(drive, kIOServicePlane, &drive_media);
98             if (unlikely(status != KERN_SUCCESS)) {
99                 IOObjectRelease(drive);
100                 continue;
101             }
102
103             /* Get drive media properties. */
104             if (likely(!IORegistryEntryCreateCFProperties(drive_media, (CFMutableDictionaryRef *)&properties, kCFAllocatorDefault, 0))) {
105                 /* Get disk name. */
106                 if (likely(name = (CFStringRef)CFDictionaryGetValue(properties, CFSTR(kIOBSDNameKey)))) {
107                     CFStringGetCString(name, diskstat.name, MAXDRIVENAME, kCFStringEncodingUTF8);
108                 }
109             }
110
111             /* Release. */
112             CFRelease(properties);
113             IOObjectRelease(drive_media);
114
115             /* Obtain the properties for this drive object. */
116             if (unlikely(IORegistryEntryCreateCFProperties(drive, (CFMutableDictionaryRef *)&properties, kCFAllocatorDefault, 0))) {
117                 error("MACOS: IORegistryEntryCreateCFProperties() failed");
118                 do_io = 0;
119                 error("DISABLED: system.io");
120                 break;
121             } else if (likely(properties)) {
122                 /* Obtain the statistics from the drive properties. */
123                 if (likely(statistics = (CFDictionaryRef)CFDictionaryGetValue(properties, CFSTR(kIOBlockStorageDriverStatisticsKey)))) {
124
125                     // --------------------------------------------------------------------
126
127                     /* Get bytes read. */
128                     if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)))) {
129                         CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.bytes_read);
130                         total_disk_reads += diskstat.bytes_read;
131                     }
132
133                     /* Get bytes written. */
134                     if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)))) {
135                         CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.bytes_write);
136                         total_disk_writes += diskstat.bytes_write;
137                     }
138
139                     st = rrdset_find_bytype_localhost("disk", diskstat.name);
140                     if (unlikely(!st)) {
141                         st = rrdset_create_localhost("disk", diskstat.name, NULL, diskstat.name, "disk.io"
142                                                      , "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every
143                                                      , RRDSET_TYPE_AREA);
144
145                         rrddim_add(st, "reads", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
146                         rrddim_add(st, "writes", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
147                     }
148                     else rrdset_next(st);
149
150                     prev_diskstat.bytes_read = rrddim_set(st, "reads", diskstat.bytes_read);
151                     prev_diskstat.bytes_write = rrddim_set(st, "writes", diskstat.bytes_write);
152                     rrdset_done(st);
153
154                     // --------------------------------------------------------------------
155
156                     /* Get number of reads. */
157                     if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsReadsKey)))) {
158                         CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.reads);
159                     }
160
161                     /* Get number of writes. */
162                     if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsWritesKey)))) {
163                         CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.writes);
164                     }
165
166                     st = rrdset_find_bytype_localhost("disk_ops", diskstat.name);
167                     if (unlikely(!st)) {
168                         st = rrdset_create_localhost("disk_ops", diskstat.name, NULL, diskstat.name, "disk.ops"
169                                                      , "Disk Completed I/O Operations", "operations/s", 2001
170                                                      , update_every, RRDSET_TYPE_LINE);
171                         rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
172
173                         rrddim_add(st, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
174                         rrddim_add(st, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
175                     }
176                     else rrdset_next(st);
177
178                     prev_diskstat.operations_read = rrddim_set(st, "reads", diskstat.reads);
179                     prev_diskstat.operations_write = rrddim_set(st, "writes", diskstat.writes);
180                     rrdset_done(st);
181
182                     // --------------------------------------------------------------------
183
184                     /* Get reads time. */
185                     if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsTotalReadTimeKey)))) {
186                         CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.time_read);
187                     }
188
189                     /* Get writes time. */
190                     if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsTotalWriteTimeKey)))) {
191                         CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.time_write);
192                     }
193
194                     st = rrdset_find_bytype_localhost("disk_util", diskstat.name);
195                     if (unlikely(!st)) {
196                         st = rrdset_create_localhost("disk_util", diskstat.name, NULL, diskstat.name, "disk.util"
197                                                      , "Disk Utilization Time", "% of time working", 2004, update_every
198                                                      , RRDSET_TYPE_AREA);
199                         rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
200
201                         rrddim_add(st, "utilization", NULL, 1, 10000000, RRD_ALGORITHM_INCREMENTAL);
202                     }
203                     else rrdset_next(st);
204
205                     cur_diskstat.busy_time_ns = (diskstat.time_read + diskstat.time_write);
206                     prev_diskstat.busy_time_ns = rrddim_set(st, "utilization", cur_diskstat.busy_time_ns);
207                     rrdset_done(st);
208
209                     // --------------------------------------------------------------------
210
211                     /* Get reads latency. */
212                     if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsLatentReadTimeKey)))) {
213                         CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.latency_read);
214                     }
215
216                     /* Get writes latency. */
217                     if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsLatentWriteTimeKey)))) {
218                         CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.latency_write);
219                     }
220
221                     st = rrdset_find_bytype_localhost("disk_iotime", diskstat.name);
222                     if (unlikely(!st)) {
223                         st = rrdset_create_localhost("disk_iotime", diskstat.name, NULL, diskstat.name, "disk.iotime"
224                                                      , "Disk Total I/O Time", "milliseconds/s", 2022, update_every
225                                                      , RRDSET_TYPE_LINE);
226                         rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
227
228                         rrddim_add(st, "reads", NULL, 1, 1000000, RRD_ALGORITHM_INCREMENTAL);
229                         rrddim_add(st, "writes", NULL, -1, 1000000, RRD_ALGORITHM_INCREMENTAL);
230                     }
231                     else rrdset_next(st);
232
233                     cur_diskstat.duration_read_ns = diskstat.time_read + diskstat.latency_read;
234                     cur_diskstat.duration_write_ns = diskstat.time_write + diskstat.latency_write;
235                     prev_diskstat.duration_read_ns = rrddim_set(st, "reads", cur_diskstat.duration_read_ns);
236                     prev_diskstat.duration_write_ns = rrddim_set(st, "writes", cur_diskstat.duration_write_ns);
237                     rrdset_done(st);
238
239                     // --------------------------------------------------------------------
240                     // calculate differential charts
241                     // only if this is not the first time we run
242
243                     if (likely(dt)) {
244
245                         // --------------------------------------------------------------------
246
247                         st = rrdset_find_bytype_localhost("disk_await", diskstat.name);
248                         if (unlikely(!st)) {
249                             st = rrdset_create_localhost("disk_await", diskstat.name, NULL, diskstat.name, "disk.await"
250                                                          , "Average Completed I/O Operation Time", "ms per operation"
251                                                          , 2005, update_every, RRDSET_TYPE_LINE);
252                             rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
253
254                             rrddim_add(st, "reads", NULL, 1, 1000000, RRD_ALGORITHM_ABSOLUTE);
255                             rrddim_add(st, "writes", NULL, -1, 1000000, RRD_ALGORITHM_ABSOLUTE);
256                         }
257                         else rrdset_next(st);
258
259                         rrddim_set(st, "reads", (diskstat.reads - prev_diskstat.operations_read) ?
260                             (cur_diskstat.duration_read_ns - prev_diskstat.duration_read_ns) / (diskstat.reads - prev_diskstat.operations_read) : 0);
261                         rrddim_set(st, "writes", (diskstat.writes - prev_diskstat.operations_write) ?
262                             (cur_diskstat.duration_write_ns - prev_diskstat.duration_write_ns) / (diskstat.writes - prev_diskstat.operations_write) : 0);
263                         rrdset_done(st);
264
265                         // --------------------------------------------------------------------
266
267                         st = rrdset_find_bytype_localhost("disk_avgsz", diskstat.name);
268                         if (unlikely(!st)) {
269                             st = rrdset_create_localhost("disk_avgsz", diskstat.name, NULL, diskstat.name, "disk.avgsz"
270                                                          , "Average Completed I/O Operation Bandwidth"
271                                                          , "kilobytes per operation", 2006, update_every
272                                                          , RRDSET_TYPE_AREA);
273                             rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
274
275                             rrddim_add(st, "reads", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
276                             rrddim_add(st, "writes", NULL, -1, 1024, RRD_ALGORITHM_ABSOLUTE);
277                         }
278                         else rrdset_next(st);
279
280                         rrddim_set(st, "reads", (diskstat.reads - prev_diskstat.operations_read) ?
281                             (diskstat.bytes_read - prev_diskstat.bytes_read) / (diskstat.reads - prev_diskstat.operations_read) : 0);
282                         rrddim_set(st, "writes", (diskstat.writes - prev_diskstat.operations_write) ?
283                             (diskstat.bytes_write - prev_diskstat.bytes_write) / (diskstat.writes - prev_diskstat.operations_write) : 0);
284                         rrdset_done(st);
285
286                         // --------------------------------------------------------------------
287
288                         st = rrdset_find_bytype_localhost("disk_svctm", diskstat.name);
289                         if (unlikely(!st)) {
290                             st = rrdset_create_localhost("disk_svctm", diskstat.name, NULL, diskstat.name, "disk.svctm"
291                                                          , "Average Service Time", "ms per operation", 2007
292                                                          , update_every, RRDSET_TYPE_LINE);
293                             rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
294
295                             rrddim_add(st, "svctm", NULL, 1, 1000000, RRD_ALGORITHM_ABSOLUTE);
296                         }
297                         else rrdset_next(st);
298
299                         rrddim_set(st, "svctm", ((diskstat.reads - prev_diskstat.operations_read) + (diskstat.writes - prev_diskstat.operations_write)) ?
300                             (cur_diskstat.busy_time_ns - prev_diskstat.busy_time_ns) / ((diskstat.reads - prev_diskstat.operations_read) + (diskstat.writes - prev_diskstat.operations_write)) : 0);
301                         rrdset_done(st);
302                     }
303                 }
304
305                 /* Release. */
306                 CFRelease(properties);
307             }
308
309             /* Release. */
310             IOObjectRelease(drive);
311         }
312         IOIteratorReset(drive_list);
313
314         /* Release. */
315         IOObjectRelease(drive_list);
316     }
317
318     if (likely(do_io)) {
319         st = rrdset_find_bytype_localhost("system", "io");
320         if (unlikely(!st)) {
321             st = rrdset_create_localhost("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150
322                                          , update_every, RRDSET_TYPE_AREA);
323             rrddim_add(st, "in",  NULL,  1, 1024, RRD_ALGORITHM_INCREMENTAL);
324             rrddim_add(st, "out", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
325         }
326         else rrdset_next(st);
327
328         rrddim_set(st, "in", total_disk_reads);
329         rrddim_set(st, "out", total_disk_writes);
330         rrdset_done(st);
331     }
332
333     // Can be merged with FreeBSD plugin
334     // --------------------------------------------------------------------------
335
336     if (likely(do_space || do_inodes)) {
337         // there is no mount info in sysctl MIBs
338         if (unlikely(!(mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)))) {
339             error("MACOS: getmntinfo() failed");
340             do_space = 0;
341             error("DISABLED: disk_space.X");
342             do_inodes = 0;
343             error("DISABLED: disk_inodes.X");
344         } else {
345             for (i = 0; i < mntsize; i++) {
346                 if (mntbuf[i].f_flags == MNT_RDONLY ||
347                         mntbuf[i].f_blocks == 0 ||
348                         // taken from gnulib/mountlist.c and shortened to FreeBSD related fstypes
349                         strcmp(mntbuf[i].f_fstypename, "autofs") == 0 ||
350                         strcmp(mntbuf[i].f_fstypename, "procfs") == 0 ||
351                         strcmp(mntbuf[i].f_fstypename, "subfs") == 0 ||
352                         strcmp(mntbuf[i].f_fstypename, "devfs") == 0 ||
353                         strcmp(mntbuf[i].f_fstypename, "none") == 0)
354                     continue;
355
356                 // --------------------------------------------------------------------------
357
358                 if (likely(do_space)) {
359                     st = rrdset_find_bytype_localhost("disk_space", mntbuf[i].f_mntonname);
360                     if (unlikely(!st)) {
361                         snprintfz(title, 4096, "Disk Space Usage for %s [%s]", mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
362                         st = rrdset_create_localhost("disk_space", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname
363                                                      , "disk.space", title, "GB", 2023, update_every
364                                                      , RRDSET_TYPE_STACKED);
365
366                         rrddim_add(st, "avail", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
367                         rrddim_add(st, "used", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
368                         rrddim_add(st, "reserved_for_root", "reserved for root", mntbuf[i].f_bsize, GIGA_FACTOR,
369                                    RRD_ALGORITHM_ABSOLUTE);
370                     } else
371                         rrdset_next(st);
372
373                     rrddim_set(st, "avail", (collected_number) mntbuf[i].f_bavail);
374                     rrddim_set(st, "used", (collected_number) (mntbuf[i].f_blocks - mntbuf[i].f_bfree));
375                     rrddim_set(st, "reserved_for_root", (collected_number) (mntbuf[i].f_bfree - mntbuf[i].f_bavail));
376                     rrdset_done(st);
377                 }
378
379                 // --------------------------------------------------------------------------
380
381                 if (likely(do_inodes)) {
382                     st = rrdset_find_bytype_localhost("disk_inodes", mntbuf[i].f_mntonname);
383                     if (unlikely(!st)) {
384                         snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]", mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
385                         st = rrdset_create_localhost("disk_inodes", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname
386                                                      , "disk.inodes", title, "Inodes", 2024, update_every
387                                                      , RRDSET_TYPE_STACKED);
388
389                         rrddim_add(st, "avail", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
390                         rrddim_add(st, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
391                         rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRD_ALGORITHM_ABSOLUTE);
392                     } else
393                         rrdset_next(st);
394
395                     rrddim_set(st, "avail", (collected_number) mntbuf[i].f_ffree);
396                     rrddim_set(st, "used", (collected_number) (mntbuf[i].f_files - mntbuf[i].f_ffree));
397                     rrdset_done(st);
398                 }
399             }
400         }
401     }
402
403     // Can be merged with FreeBSD plugin
404     // --------------------------------------------------------------------
405
406     if (likely(do_bandwidth)) {
407         if (unlikely(getifaddrs(&ifap))) {
408             error("MACOS: getifaddrs()");
409             do_bandwidth = 0;
410             error("DISABLED: system.ipv4");
411         } else {
412             for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
413                 if (ifa->ifa_addr->sa_family != AF_LINK)
414                         continue;
415
416                 // --------------------------------------------------------------------
417
418                 st = rrdset_find_bytype_localhost("net", ifa->ifa_name);
419                 if (unlikely(!st)) {
420                     st = rrdset_create_localhost("net", ifa->ifa_name, NULL, ifa->ifa_name, "net.net", "Bandwidth"
421                                                  , "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA);
422
423                     rrddim_add(st, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
424                     rrddim_add(st, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
425                 }
426                 else rrdset_next(st);
427
428                 rrddim_set(st, "received", IFA_DATA(ibytes));
429                 rrddim_set(st, "sent", IFA_DATA(obytes));
430                 rrdset_done(st);
431
432                 // --------------------------------------------------------------------
433
434                 st = rrdset_find_bytype_localhost("net_packets", ifa->ifa_name);
435                 if (unlikely(!st)) {
436                     st = rrdset_create_localhost("net_packets", ifa->ifa_name, NULL, ifa->ifa_name, "net.packets"
437                                                  , "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE);
438                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
439
440                     rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
441                     rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
442                     rrddim_add(st, "multicast_received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
443                     rrddim_add(st, "multicast_sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
444                 }
445                 else rrdset_next(st);
446
447                 rrddim_set(st, "received", IFA_DATA(ipackets));
448                 rrddim_set(st, "sent", IFA_DATA(opackets));
449                 rrddim_set(st, "multicast_received", IFA_DATA(imcasts));
450                 rrddim_set(st, "multicast_sent", IFA_DATA(omcasts));
451                 rrdset_done(st);
452
453                 // --------------------------------------------------------------------
454
455                 st = rrdset_find_bytype_localhost("net_errors", ifa->ifa_name);
456                 if (unlikely(!st)) {
457                     st = rrdset_create_localhost("net_errors", ifa->ifa_name, NULL, ifa->ifa_name, "net.errors"
458                                                  , "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE);
459                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
460
461                     rrddim_add(st, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
462                     rrddim_add(st, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
463                 }
464                 else rrdset_next(st);
465
466                 rrddim_set(st, "inbound", IFA_DATA(ierrors));
467                 rrddim_set(st, "outbound", IFA_DATA(oerrors));
468                 rrdset_done(st);
469
470                 // --------------------------------------------------------------------
471
472                 st = rrdset_find_bytype_localhost("net_drops", ifa->ifa_name);
473                 if (unlikely(!st)) {
474                     st = rrdset_create_localhost("net_drops", ifa->ifa_name, NULL, ifa->ifa_name, "net.drops"
475                                                  , "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE);
476                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
477
478                     rrddim_add(st, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
479                 }
480                 else rrdset_next(st);
481
482                 rrddim_set(st, "inbound", IFA_DATA(iqdrops));
483                 rrdset_done(st);
484
485                 // --------------------------------------------------------------------
486
487                 st = rrdset_find_bytype_localhost("net_events", ifa->ifa_name);
488                 if (unlikely(!st)) {
489                     st = rrdset_create_localhost("net_events", ifa->ifa_name, NULL, ifa->ifa_name, "net.events"
490                                                  , "Network Interface Events", "events/s", 7006, update_every
491                                                  , RRDSET_TYPE_LINE);
492                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
493
494                     rrddim_add(st, "frames", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
495                     rrddim_add(st, "collisions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
496                     rrddim_add(st, "carrier", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
497                 }
498                 else rrdset_next(st);
499
500                 rrddim_set(st, "collisions", IFA_DATA(collisions));
501                 rrdset_done(st);
502             }
503
504             freeifaddrs(ifap);
505         }
506     }
507
508
509     return 0;
510 }