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>
10 #define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
12 // MacOS calculates load averages once every 5 seconds
13 #define MIN_LOADAVG_UPDATE_EVERY 5
15 int getsysctl(const char *name, void *ptr, size_t len);
17 int do_macos_sysctl(int update_every, usec_t dt) {
20 static int do_loadavg = -1, do_swap = -1, do_bandwidth = -1,
21 do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1, do_ecn = -1,
22 do_tcpext_syscookies = -1, do_tcpext_ofo = -1, do_tcpext_connaborts = -1;
25 if (unlikely(do_loadavg == -1)) {
26 do_loadavg = config_get_boolean("plugin:macos:sysctl", "enable load average", 1);
27 do_swap = config_get_boolean("plugin:macos:sysctl", "system swap", 1);
28 do_bandwidth = config_get_boolean("plugin:macos:sysctl", "bandwidth", 1);
29 do_tcp_packets = config_get_boolean("plugin:macos:sysctl", "ipv4 TCP packets", 1);
30 do_tcp_errors = config_get_boolean("plugin:macos:sysctl", "ipv4 TCP errors", 1);
31 do_tcp_handshake = config_get_boolean("plugin:macos:sysctl", "ipv4 TCP handshake issues", 1);
32 do_ecn = config_get_boolean_ondemand("plugin:macos:sysctl", "ECN packets", CONFIG_ONDEMAND_ONDEMAND);
33 do_tcpext_syscookies = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP SYN cookies", CONFIG_ONDEMAND_ONDEMAND);
34 do_tcpext_ofo = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP out-of-order queue", CONFIG_ONDEMAND_ONDEMAND);
35 do_tcpext_connaborts = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP connection aborts", CONFIG_ONDEMAND_ONDEMAND);
40 int system_pagesize = getpagesize(); // wouldn't it be better to get value directly from hw.pagesize?
45 // NEEDED BY: do_loadavg
46 static usec_t last_loadavg_usec = 0;
47 struct loadavg sysload;
50 struct xsw_usage swap_usage;
52 // NEEDED BY: do_bandwidth
54 static char *ifstatdata = NULL;
56 struct if_msghdr *ifm;
62 // NEEDED BY: do_tcp...
63 struct tcpstat tcpstat;
64 uint64_t tcps_states[TCP_NSTATES];
66 if (last_loadavg_usec <= dt) {
67 if (likely(do_loadavg)) {
68 if (unlikely(GETSYSCTL("vm.loadavg", sysload))) {
70 error("DISABLED: system.load");
73 st = rrdset_find_bytype("system", "load");
75 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);
76 rrddim_add(st, "load1", NULL, 1, 1000, RRDDIM_ABSOLUTE);
77 rrddim_add(st, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
78 rrddim_add(st, "load15", NULL, 1, 1000, RRDDIM_ABSOLUTE);
82 rrddim_set(st, "load1", (collected_number) ((double)sysload.ldavg[0] / sysload.fscale * 1000));
83 rrddim_set(st, "load5", (collected_number) ((double)sysload.ldavg[1] / sysload.fscale * 1000));
84 rrddim_set(st, "load15", (collected_number) ((double)sysload.ldavg[2] / sysload.fscale * 1000));
89 last_loadavg_usec = st->update_every * USEC_PER_SEC;
91 else last_loadavg_usec -= dt;
93 if (likely(do_swap)) {
94 if (unlikely(GETSYSCTL("vm.swapusage", swap_usage))) {
96 error("DISABLED: system.swap");
98 st = rrdset_find("system.swap");
100 st = rrdset_create("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201, update_every, RRDSET_TYPE_STACKED);
103 rrddim_add(st, "free", NULL, 1, 1048576, RRDDIM_ABSOLUTE);
104 rrddim_add(st, "used", NULL, 1, 1048576, RRDDIM_ABSOLUTE);
106 else rrdset_next(st);
108 rrddim_set(st, "free", swap_usage.xsu_avail);
109 rrddim_set(st, "used", swap_usage.xsu_used);
114 // --------------------------------------------------------------------
116 if (likely(do_bandwidth)) {
121 mib[4] = NET_RT_IFLIST2;
123 if (unlikely(sysctl(mib, 6, NULL, &size, NULL, 0))) {
124 error("MACOS: sysctl(%s...) failed: %s", "net interfaces", strerror(errno));
126 error("DISABLED: system.ipv4");
128 ifstatdata = reallocz(ifstatdata, size);
129 if (unlikely(sysctl(mib, 6, ifstatdata, &size, NULL, 0) < 0)) {
130 error("MACOS: sysctl(%s...) failed: %s", "net interfaces", strerror(errno));
132 error("DISABLED: system.ipv4");
134 lim = ifstatdata + size;
135 iftot.ift_ibytes = iftot.ift_obytes = 0;
136 for (next = ifstatdata; next < lim; ) {
137 ifm = (struct if_msghdr *)next;
138 next += ifm->ifm_msglen;
140 if (ifm->ifm_type == RTM_IFINFO2) {
141 struct if_msghdr2 *if2m = (struct if_msghdr2 *)ifm;
143 iftot.ift_ibytes += if2m->ifm_data.ifi_ibytes;
144 iftot.ift_obytes += if2m->ifm_data.ifi_obytes;
147 st = rrdset_find("system.ipv4");
149 st = rrdset_create("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
151 rrddim_add(st, "InOctets", "received", 8, 1024, RRDDIM_INCREMENTAL);
152 rrddim_add(st, "OutOctets", "sent", -8, 1024, RRDDIM_INCREMENTAL);
154 else rrdset_next(st);
156 rrddim_set(st, "InOctets", iftot.ift_ibytes);
157 rrddim_set(st, "OutOctets", iftot.ift_obytes);
163 // --------------------------------------------------------------------
165 // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
166 if (likely(do_tcp_packets || do_tcp_errors || do_tcp_handshake || do_tcpext_connaborts || do_tcpext_ofo || do_tcpext_syscookies || do_ecn)) {
167 if (unlikely(GETSYSCTL("net.inet.tcp.stats", tcpstat))){
169 error("DISABLED: ipv4.tcppackets");
171 error("DISABLED: ipv4.tcperrors");
172 do_tcp_handshake = 0;
173 error("DISABLED: ipv4.tcphandshake");
174 do_tcpext_connaborts = 0;
175 error("DISABLED: ipv4.tcpconnaborts");
177 error("DISABLED: ipv4.tcpofo");
178 do_tcpext_syscookies = 0;
179 error("DISABLED: ipv4.tcpsyncookies");
181 error("DISABLED: ipv4.ecnpkts");
183 if (likely(do_tcp_packets)) {
184 st = rrdset_find("ipv4.tcppackets");
186 st = rrdset_create("ipv4", "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets",
188 2600, update_every, RRDSET_TYPE_LINE);
190 rrddim_add(st, "InSegs", "received", 1, 1, RRDDIM_INCREMENTAL);
191 rrddim_add(st, "OutSegs", "sent", -1, 1, RRDDIM_INCREMENTAL);
195 rrddim_set(st, "InSegs", tcpstat.tcps_rcvtotal);
196 rrddim_set(st, "OutSegs", tcpstat.tcps_sndtotal);
200 // --------------------------------------------------------------------
202 if (likely(do_tcp_errors)) {
203 st = rrdset_find("ipv4.tcperrors");
205 st = rrdset_create("ipv4", "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors",
207 2700, update_every, RRDSET_TYPE_LINE);
210 rrddim_add(st, "InErrs", NULL, 1, 1, RRDDIM_INCREMENTAL);
211 rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
212 rrddim_add(st, "RetransSegs", NULL, -1, 1, RRDDIM_INCREMENTAL);
216 rrddim_set(st, "InErrs", tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvshort);
217 rrddim_set(st, "InCsumErrors", tcpstat.tcps_rcvbadsum);
218 rrddim_set(st, "RetransSegs", tcpstat.tcps_sndrexmitpack);
222 // --------------------------------------------------------------------
224 if (likely(do_tcp_handshake)) {
225 st = rrdset_find("ipv4.tcphandshake");
227 st = rrdset_create("ipv4", "tcphandshake", NULL, "tcp", NULL,
228 "IPv4 TCP Handshake Issues",
229 "events/s", 2900, update_every, RRDSET_TYPE_LINE);
232 rrddim_add(st, "EstabResets", NULL, 1, 1, RRDDIM_INCREMENTAL);
233 rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
234 rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
235 rrddim_add(st, "AttemptFails", NULL, 1, 1, RRDDIM_INCREMENTAL);
239 rrddim_set(st, "EstabResets", tcpstat.tcps_drops);
240 rrddim_set(st, "ActiveOpens", tcpstat.tcps_connattempt);
241 rrddim_set(st, "PassiveOpens", tcpstat.tcps_accepts);
242 rrddim_set(st, "AttemptFails", tcpstat.tcps_conndrops);
246 // --------------------------------------------------------------------
248 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))) {
249 do_tcpext_connaborts = CONFIG_ONDEMAND_YES;
250 st = rrdset_find("ipv4.tcpconnaborts");
252 st = rrdset_create("ipv4", "tcpconnaborts", NULL, "tcp", NULL, "TCP Connection Aborts", "connections/s", 3010, update_every, RRDSET_TYPE_LINE);
254 rrddim_add(st, "TCPAbortOnData", "baddata", 1, 1, RRDDIM_INCREMENTAL);
255 rrddim_add(st, "TCPAbortOnClose", "userclosed", 1, 1, RRDDIM_INCREMENTAL);
256 rrddim_add(st, "TCPAbortOnMemory", "nomemory", 1, 1, RRDDIM_INCREMENTAL);
257 rrddim_add(st, "TCPAbortOnTimeout", "timeout", 1, 1, RRDDIM_INCREMENTAL);
259 else rrdset_next(st);
261 rrddim_set(st, "TCPAbortOnData", tcpstat.tcps_rcvpackafterwin);
262 rrddim_set(st, "TCPAbortOnClose", tcpstat.tcps_rcvafterclose);
263 rrddim_set(st, "TCPAbortOnMemory", tcpstat.tcps_rcvmemdrop);
264 rrddim_set(st, "TCPAbortOnTimeout", tcpstat.tcps_persistdrop);
268 // --------------------------------------------------------------------
270 if (do_tcpext_ofo == CONFIG_ONDEMAND_YES || (do_tcpext_ofo == CONFIG_ONDEMAND_ONDEMAND && tcpstat.tcps_rcvoopack)) {
271 do_tcpext_ofo = CONFIG_ONDEMAND_YES;
272 st = rrdset_find("ipv4.tcpofo");
274 st = rrdset_create("ipv4", "tcpofo", NULL, "tcp", NULL, "TCP Out-Of-Order Queue", "packets/s", 3050, update_every, RRDSET_TYPE_LINE);
276 rrddim_add(st, "TCPOFOQueue", "inqueue", 1, 1, RRDDIM_INCREMENTAL);
278 else rrdset_next(st);
280 rrddim_set(st, "TCPOFOQueue", tcpstat.tcps_rcvoopack);
284 // --------------------------------------------------------------------
286 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))) {
287 do_tcpext_syscookies = CONFIG_ONDEMAND_YES;
289 st = rrdset_find("ipv4.tcpsyncookies");
291 st = rrdset_create("ipv4", "tcpsyncookies", NULL, "tcp", NULL, "TCP SYN Cookies", "packets/s", 3100, update_every, RRDSET_TYPE_LINE);
293 rrddim_add(st, "SyncookiesRecv", "received", 1, 1, RRDDIM_INCREMENTAL);
294 rrddim_add(st, "SyncookiesSent", "sent", -1, 1, RRDDIM_INCREMENTAL);
295 rrddim_add(st, "SyncookiesFailed", "failed", -1, 1, RRDDIM_INCREMENTAL);
297 else rrdset_next(st);
299 rrddim_set(st, "SyncookiesRecv", tcpstat.tcps_sc_recvcookie);
300 rrddim_set(st, "SyncookiesSent", tcpstat.tcps_sc_sendcookie);
301 rrddim_set(st, "SyncookiesFailed", tcpstat.tcps_sc_zonefail);
305 // --------------------------------------------------------------------
307 if (do_ecn == CONFIG_ONDEMAND_YES || (do_ecn == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_ecn_recv_ce || tcpstat.tcps_ecn_not_supported))) {
308 do_ecn = CONFIG_ONDEMAND_YES;
309 st = rrdset_find("ipv4.ecnpkts");
311 st = rrdset_create("ipv4", "ecnpkts", NULL, "ecn", NULL, "IPv4 ECN Statistics", "packets/s", 8700, update_every, RRDSET_TYPE_LINE);
314 rrddim_add(st, "InCEPkts", "CEP", 1, 1, RRDDIM_INCREMENTAL);
315 rrddim_add(st, "InNoECTPkts", "NoECTP", -1, 1, RRDDIM_INCREMENTAL);
317 else rrdset_next(st);
319 rrddim_set(st, "InCEPkts", tcpstat.tcps_ecn_recv_ce);
320 rrddim_set(st, "InNoECTPkts", tcpstat.tcps_ecn_not_supported);
330 int getsysctl(const char *name, void *ptr, size_t len)
334 if (unlikely(sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)) {
335 error("MACOS: sysctl(%s...) failed: %s", name, strerror(errno));
338 if (unlikely(nlen != len)) {
339 error("MACOS: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);