2 #include <sys/sysctl.h>
3 // NEEDED BY: do_bandwidth
6 #include <sys/socketvar.h>
7 #include <netinet/tcp_var.h>
8 #include <netinet/tcp_fsm.h>
9 // NEEDED BY do_udp..., do_ip...
10 #include <netinet/ip_var.h>
11 // NEEDED BY do_udp...
12 #include <netinet/udp.h>
13 #include <netinet/udp_var.h>
14 // NEEDED BY do_icmp...
15 #include <netinet/ip.h>
16 #include <netinet/ip_icmp.h>
17 #include <netinet/icmp_var.h>
19 #define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
21 // MacOS calculates load averages once every 5 seconds
22 #define MIN_LOADAVG_UPDATE_EVERY 5
24 int getsysctl(const char *name, void *ptr, size_t len);
26 int do_macos_sysctl(int update_every, usec_t dt) {
29 static int do_loadavg = -1, do_swap = -1, do_bandwidth = -1,
30 do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1, do_ecn = -1,
31 do_tcpext_syscookies = -1, do_tcpext_ofo = -1, do_tcpext_connaborts = -1,
32 do_udp_packets = -1, do_udp_errors = -1, do_icmp_packets = -1, do_icmpmsg = -1;
35 if (unlikely(do_loadavg == -1)) {
36 do_loadavg = config_get_boolean("plugin:macos:sysctl", "enable load average", 1);
37 do_swap = config_get_boolean("plugin:macos:sysctl", "system swap", 1);
38 do_bandwidth = config_get_boolean("plugin:macos:sysctl", "bandwidth", 1);
39 do_tcp_packets = config_get_boolean("plugin:macos:sysctl", "ipv4 TCP packets", 1);
40 do_tcp_errors = config_get_boolean("plugin:macos:sysctl", "ipv4 TCP errors", 1);
41 do_tcp_handshake = config_get_boolean("plugin:macos:sysctl", "ipv4 TCP handshake issues", 1);
42 do_ecn = config_get_boolean_ondemand("plugin:macos:sysctl", "ECN packets", CONFIG_ONDEMAND_ONDEMAND);
43 do_tcpext_syscookies = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP SYN cookies", CONFIG_ONDEMAND_ONDEMAND);
44 do_tcpext_ofo = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP out-of-order queue", CONFIG_ONDEMAND_ONDEMAND);
45 do_tcpext_connaborts = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP connection aborts", CONFIG_ONDEMAND_ONDEMAND);
46 do_udp_packets = config_get_boolean("plugin:macos:sysctl", "ipv4 UDP packets", 1);
47 do_udp_errors = config_get_boolean("plugin:macos:sysctl", "ipv4 UDP errors", 1);
48 do_icmp_packets = config_get_boolean("plugin:macos:sysctl", "ipv4 ICMP packets", 1);
49 do_icmpmsg = config_get_boolean("plugin:macos:sysctl", "ipv4 ICMP messages", 1);
54 int system_pagesize = getpagesize(); // wouldn't it be better to get value directly from hw.pagesize?
59 // NEEDED BY: do_loadavg
60 static usec_t last_loadavg_usec = 0;
61 struct loadavg sysload;
64 struct xsw_usage swap_usage;
66 // NEEDED BY: do_bandwidth
68 static char *ifstatdata = NULL;
70 struct if_msghdr *ifm;
76 // NEEDED BY: do_tcp...
77 struct tcpstat tcpstat;
78 uint64_t tcps_states[TCP_NSTATES];
80 // NEEDED BY: do_udp...
81 struct udpstat udpstat;
83 // NEEDED BY: do_icmp...
84 struct icmpstat icmpstat;
88 } icmp_total = {0, 0};
90 // --------------------------------------------------------------------
92 if (last_loadavg_usec <= dt) {
93 if (likely(do_loadavg)) {
94 if (unlikely(GETSYSCTL("vm.loadavg", sysload))) {
96 error("DISABLED: system.load");
99 st = rrdset_find_bytype("system", "load");
101 st = rrdset_create("system", "load", NULL, "load", NULL, "System Load Average", "load", 100, (update_every < MIN_LOADAVG_UPDATE_EVERY) ? MIN_LOADAVG_UPDATE_EVERY : update_every, RRDSET_TYPE_LINE);
102 rrddim_add(st, "load1", NULL, 1, 1000, RRDDIM_ABSOLUTE);
103 rrddim_add(st, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
104 rrddim_add(st, "load15", NULL, 1, 1000, RRDDIM_ABSOLUTE);
106 else rrdset_next(st);
108 rrddim_set(st, "load1", (collected_number) ((double)sysload.ldavg[0] / sysload.fscale * 1000));
109 rrddim_set(st, "load5", (collected_number) ((double)sysload.ldavg[1] / sysload.fscale * 1000));
110 rrddim_set(st, "load15", (collected_number) ((double)sysload.ldavg[2] / sysload.fscale * 1000));
115 last_loadavg_usec = st->update_every * USEC_PER_SEC;
117 else last_loadavg_usec -= dt;
119 // --------------------------------------------------------------------
121 if (likely(do_swap)) {
122 if (unlikely(GETSYSCTL("vm.swapusage", swap_usage))) {
124 error("DISABLED: system.swap");
126 st = rrdset_find("system.swap");
128 st = rrdset_create("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201, update_every, RRDSET_TYPE_STACKED);
131 rrddim_add(st, "free", NULL, 1, 1048576, RRDDIM_ABSOLUTE);
132 rrddim_add(st, "used", NULL, 1, 1048576, RRDDIM_ABSOLUTE);
134 else rrdset_next(st);
136 rrddim_set(st, "free", swap_usage.xsu_avail);
137 rrddim_set(st, "used", swap_usage.xsu_used);
142 // --------------------------------------------------------------------
144 if (likely(do_bandwidth)) {
149 mib[4] = NET_RT_IFLIST2;
151 if (unlikely(sysctl(mib, 6, NULL, &size, NULL, 0))) {
152 error("MACOS: sysctl(%s...) failed: %s", "net interfaces", strerror(errno));
154 error("DISABLED: system.ipv4");
156 ifstatdata = reallocz(ifstatdata, size);
157 if (unlikely(sysctl(mib, 6, ifstatdata, &size, NULL, 0) < 0)) {
158 error("MACOS: sysctl(%s...) failed: %s", "net interfaces", strerror(errno));
160 error("DISABLED: system.ipv4");
162 lim = ifstatdata + size;
163 iftot.ift_ibytes = iftot.ift_obytes = 0;
164 for (next = ifstatdata; next < lim; ) {
165 ifm = (struct if_msghdr *)next;
166 next += ifm->ifm_msglen;
168 if (ifm->ifm_type == RTM_IFINFO2) {
169 struct if_msghdr2 *if2m = (struct if_msghdr2 *)ifm;
171 iftot.ift_ibytes += if2m->ifm_data.ifi_ibytes;
172 iftot.ift_obytes += if2m->ifm_data.ifi_obytes;
175 st = rrdset_find("system.ipv4");
177 st = rrdset_create("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
179 rrddim_add(st, "InOctets", "received", 8, 1024, RRDDIM_INCREMENTAL);
180 rrddim_add(st, "OutOctets", "sent", -8, 1024, RRDDIM_INCREMENTAL);
182 else rrdset_next(st);
184 rrddim_set(st, "InOctets", iftot.ift_ibytes);
185 rrddim_set(st, "OutOctets", iftot.ift_obytes);
191 // --------------------------------------------------------------------
193 // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
194 if (likely(do_tcp_packets || do_tcp_errors || do_tcp_handshake || do_tcpext_connaborts || do_tcpext_ofo || do_tcpext_syscookies || do_ecn)) {
195 if (unlikely(GETSYSCTL("net.inet.tcp.stats", tcpstat))){
197 error("DISABLED: ipv4.tcppackets");
199 error("DISABLED: ipv4.tcperrors");
200 do_tcp_handshake = 0;
201 error("DISABLED: ipv4.tcphandshake");
202 do_tcpext_connaborts = 0;
203 error("DISABLED: ipv4.tcpconnaborts");
205 error("DISABLED: ipv4.tcpofo");
206 do_tcpext_syscookies = 0;
207 error("DISABLED: ipv4.tcpsyncookies");
209 error("DISABLED: ipv4.ecnpkts");
211 if (likely(do_tcp_packets)) {
212 st = rrdset_find("ipv4.tcppackets");
214 st = rrdset_create("ipv4", "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets",
216 2600, update_every, RRDSET_TYPE_LINE);
218 rrddim_add(st, "InSegs", "received", 1, 1, RRDDIM_INCREMENTAL);
219 rrddim_add(st, "OutSegs", "sent", -1, 1, RRDDIM_INCREMENTAL);
223 rrddim_set(st, "InSegs", tcpstat.tcps_rcvtotal);
224 rrddim_set(st, "OutSegs", tcpstat.tcps_sndtotal);
228 // --------------------------------------------------------------------
230 if (likely(do_tcp_errors)) {
231 st = rrdset_find("ipv4.tcperrors");
233 st = rrdset_create("ipv4", "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors",
235 2700, update_every, RRDSET_TYPE_LINE);
238 rrddim_add(st, "InErrs", NULL, 1, 1, RRDDIM_INCREMENTAL);
239 rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
240 rrddim_add(st, "RetransSegs", NULL, -1, 1, RRDDIM_INCREMENTAL);
244 rrddim_set(st, "InErrs", tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvshort);
245 rrddim_set(st, "InCsumErrors", tcpstat.tcps_rcvbadsum);
246 rrddim_set(st, "RetransSegs", tcpstat.tcps_sndrexmitpack);
250 // --------------------------------------------------------------------
252 if (likely(do_tcp_handshake)) {
253 st = rrdset_find("ipv4.tcphandshake");
255 st = rrdset_create("ipv4", "tcphandshake", NULL, "tcp", NULL,
256 "IPv4 TCP Handshake Issues",
257 "events/s", 2900, update_every, RRDSET_TYPE_LINE);
260 rrddim_add(st, "EstabResets", NULL, 1, 1, RRDDIM_INCREMENTAL);
261 rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
262 rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
263 rrddim_add(st, "AttemptFails", NULL, 1, 1, RRDDIM_INCREMENTAL);
267 rrddim_set(st, "EstabResets", tcpstat.tcps_drops);
268 rrddim_set(st, "ActiveOpens", tcpstat.tcps_connattempt);
269 rrddim_set(st, "PassiveOpens", tcpstat.tcps_accepts);
270 rrddim_set(st, "AttemptFails", tcpstat.tcps_conndrops);
274 // --------------------------------------------------------------------
276 if (do_tcpext_connaborts == CONFIG_ONDEMAND_YES || (do_tcpext_connaborts == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_rcvpackafterwin || tcpstat.tcps_rcvafterclose || tcpstat.tcps_rcvmemdrop || tcpstat.tcps_persistdrop))) {
277 do_tcpext_connaborts = CONFIG_ONDEMAND_YES;
278 st = rrdset_find("ipv4.tcpconnaborts");
280 st = rrdset_create("ipv4", "tcpconnaborts", NULL, "tcp", NULL, "TCP Connection Aborts", "connections/s", 3010, update_every, RRDSET_TYPE_LINE);
282 rrddim_add(st, "TCPAbortOnData", "baddata", 1, 1, RRDDIM_INCREMENTAL);
283 rrddim_add(st, "TCPAbortOnClose", "userclosed", 1, 1, RRDDIM_INCREMENTAL);
284 rrddim_add(st, "TCPAbortOnMemory", "nomemory", 1, 1, RRDDIM_INCREMENTAL);
285 rrddim_add(st, "TCPAbortOnTimeout", "timeout", 1, 1, RRDDIM_INCREMENTAL);
287 else rrdset_next(st);
289 rrddim_set(st, "TCPAbortOnData", tcpstat.tcps_rcvpackafterwin);
290 rrddim_set(st, "TCPAbortOnClose", tcpstat.tcps_rcvafterclose);
291 rrddim_set(st, "TCPAbortOnMemory", tcpstat.tcps_rcvmemdrop);
292 rrddim_set(st, "TCPAbortOnTimeout", tcpstat.tcps_persistdrop);
296 // --------------------------------------------------------------------
298 if (do_tcpext_ofo == CONFIG_ONDEMAND_YES || (do_tcpext_ofo == CONFIG_ONDEMAND_ONDEMAND && tcpstat.tcps_rcvoopack)) {
299 do_tcpext_ofo = CONFIG_ONDEMAND_YES;
300 st = rrdset_find("ipv4.tcpofo");
302 st = rrdset_create("ipv4", "tcpofo", NULL, "tcp", NULL, "TCP Out-Of-Order Queue", "packets/s", 3050, update_every, RRDSET_TYPE_LINE);
304 rrddim_add(st, "TCPOFOQueue", "inqueue", 1, 1, RRDDIM_INCREMENTAL);
306 else rrdset_next(st);
308 rrddim_set(st, "TCPOFOQueue", tcpstat.tcps_rcvoopack);
312 // --------------------------------------------------------------------
314 if (do_tcpext_syscookies == CONFIG_ONDEMAND_YES || (do_tcpext_syscookies == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_sc_sendcookie || tcpstat.tcps_sc_recvcookie || tcpstat.tcps_sc_zonefail))) {
315 do_tcpext_syscookies = CONFIG_ONDEMAND_YES;
317 st = rrdset_find("ipv4.tcpsyncookies");
319 st = rrdset_create("ipv4", "tcpsyncookies", NULL, "tcp", NULL, "TCP SYN Cookies", "packets/s", 3100, update_every, RRDSET_TYPE_LINE);
321 rrddim_add(st, "SyncookiesRecv", "received", 1, 1, RRDDIM_INCREMENTAL);
322 rrddim_add(st, "SyncookiesSent", "sent", -1, 1, RRDDIM_INCREMENTAL);
323 rrddim_add(st, "SyncookiesFailed", "failed", -1, 1, RRDDIM_INCREMENTAL);
325 else rrdset_next(st);
327 rrddim_set(st, "SyncookiesRecv", tcpstat.tcps_sc_recvcookie);
328 rrddim_set(st, "SyncookiesSent", tcpstat.tcps_sc_sendcookie);
329 rrddim_set(st, "SyncookiesFailed", tcpstat.tcps_sc_zonefail);
333 // --------------------------------------------------------------------
335 if (do_ecn == CONFIG_ONDEMAND_YES || (do_ecn == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_ecn_recv_ce || tcpstat.tcps_ecn_not_supported))) {
336 do_ecn = CONFIG_ONDEMAND_YES;
337 st = rrdset_find("ipv4.ecnpkts");
339 st = rrdset_create("ipv4", "ecnpkts", NULL, "ecn", NULL, "IPv4 ECN Statistics", "packets/s", 8700, update_every, RRDSET_TYPE_LINE);
342 rrddim_add(st, "InCEPkts", "CEP", 1, 1, RRDDIM_INCREMENTAL);
343 rrddim_add(st, "InNoECTPkts", "NoECTP", -1, 1, RRDDIM_INCREMENTAL);
345 else rrdset_next(st);
347 rrddim_set(st, "InCEPkts", tcpstat.tcps_ecn_recv_ce);
348 rrddim_set(st, "InNoECTPkts", tcpstat.tcps_ecn_not_supported);
355 // --------------------------------------------------------------------
357 // see http://net-snmp.sourceforge.net/docs/mibs/udp.html
358 if (likely(do_udp_packets || do_udp_errors)) {
359 if (unlikely(GETSYSCTL("net.inet.udp.stats", udpstat))) {
361 error("DISABLED: ipv4.udppackets");
363 error("DISABLED: ipv4.udperrors");
365 if (likely(do_udp_packets)) {
366 st = rrdset_find("ipv4.udppackets");
368 st = rrdset_create("ipv4", "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets",
369 "packets/s", 2601, update_every, RRDSET_TYPE_LINE);
371 rrddim_add(st, "InDatagrams", "received", 1, 1, RRDDIM_INCREMENTAL);
372 rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRDDIM_INCREMENTAL);
376 rrddim_set(st, "InDatagrams", udpstat.udps_ipackets);
377 rrddim_set(st, "OutDatagrams", udpstat.udps_opackets);
381 // --------------------------------------------------------------------
383 if (likely(do_udp_errors)) {
384 st = rrdset_find("ipv4.udperrors");
386 st = rrdset_create("ipv4", "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors", "events/s",
387 2701, update_every, RRDSET_TYPE_LINE);
390 rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
391 rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
392 rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
393 rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
394 rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRDDIM_INCREMENTAL);
398 rrddim_set(st, "InErrors", udpstat.udps_hdrops + udpstat.udps_badlen);
399 rrddim_set(st, "NoPorts", udpstat.udps_noport);
400 rrddim_set(st, "RcvbufErrors", udpstat.udps_fullsock);
401 rrddim_set(st, "InCsumErrors", udpstat.udps_badsum + udpstat.udps_nosum);
402 rrddim_set(st, "IgnoredMulti", udpstat.udps_filtermcast);
408 // --------------------------------------------------------------------
410 if (likely(do_icmp_packets || do_icmpmsg)) {
411 if (unlikely(GETSYSCTL("net.inet.icmp.stats", icmpstat))) {
413 error("DISABLED: ipv4.icmp");
414 error("DISABLED: ipv4.icmp_errors");
416 error("DISABLED: ipv4.icmpmsg");
418 for (i = 0; i <= ICMP_MAXTYPE; i++) {
419 icmp_total.msgs_in += icmpstat.icps_inhist[i];
420 icmp_total.msgs_out += icmpstat.icps_outhist[i];
422 icmp_total.msgs_in += icmpstat.icps_badcode + icmpstat.icps_badlen + icmpstat.icps_checksum + icmpstat.icps_tooshort;
424 // --------------------------------------------------------------------
426 if (likely(do_icmp_packets)) {
427 st = rrdset_find("ipv4.icmp");
429 st = rrdset_create("ipv4", "icmp", NULL, "icmp", NULL, "IPv4 ICMP Packets", "packets/s",
431 update_every, RRDSET_TYPE_LINE);
433 rrddim_add(st, "InMsgs", "received", 1, 1, RRDDIM_INCREMENTAL);
434 rrddim_add(st, "OutMsgs", "sent", -1, 1, RRDDIM_INCREMENTAL);
438 rrddim_set(st, "InMsgs", icmp_total.msgs_in);
439 rrddim_set(st, "OutMsgs", icmp_total.msgs_out);
443 // --------------------------------------------------------------------
445 st = rrdset_find("ipv4.icmp_errors");
447 st = rrdset_create("ipv4", "icmp_errors", NULL, "icmp", NULL, "IPv4 ICMP Errors",
449 2603, update_every, RRDSET_TYPE_LINE);
451 rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
452 rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
453 rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
457 rrddim_set(st, "InErrors", icmpstat.icps_badcode + icmpstat.icps_badlen + icmpstat.icps_checksum + icmpstat.icps_tooshort);
458 rrddim_set(st, "OutErrors", icmpstat.icps_error);
459 rrddim_set(st, "InCsumErrors", icmpstat.icps_checksum);
464 // --------------------------------------------------------------------
466 if (likely(do_icmpmsg)) {
467 st = rrdset_find("ipv4.icmpmsg");
469 st = rrdset_create("ipv4", "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages",
470 "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
472 rrddim_add(st, "InEchoReps", NULL, 1, 1, RRDDIM_INCREMENTAL);
473 rrddim_add(st, "OutEchoReps", NULL, -1, 1, RRDDIM_INCREMENTAL);
474 rrddim_add(st, "InEchos", NULL, 1, 1, RRDDIM_INCREMENTAL);
475 rrddim_add(st, "OutEchos", NULL, -1, 1, RRDDIM_INCREMENTAL);
479 rrddim_set(st, "InEchoReps", icmpstat.icps_inhist[ICMP_ECHOREPLY]);
480 rrddim_set(st, "OutEchoReps", icmpstat.icps_outhist[ICMP_ECHOREPLY]);
481 rrddim_set(st, "InEchos", icmpstat.icps_inhist[ICMP_ECHO]);
482 rrddim_set(st, "OutEchos", icmpstat.icps_outhist[ICMP_ECHO]);
492 int getsysctl(const char *name, void *ptr, size_t len)
496 if (unlikely(sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)) {
497 error("MACOS: sysctl(%s...) failed: %s", name, strerror(errno));
500 if (unlikely(nlen != len)) {
501 error("MACOS: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);