]> arthur.barton.de Git - netdata.git/blobdiff - src/freebsd_sysctl.c
Fix kern.cp_times bug in FreeBSD plugin
[netdata.git] / src / freebsd_sysctl.c
index 202bff1252a97dd6d32c5b67876f66f8c49a5254..4ad0d5e177dfb2633f72843cedd4823d46c9273e 100644 (file)
@@ -15,7 +15,6 @@
 // NEEDED BY: struct sysctl_netisr_workstream, struct sysctl_netisr_work
 #include <net/netisr.h>
 // NEEDED BY: struct ifaddrs, getifaddrs()
-#define _IFI_OQDROPS // It is for FreeNAS only. Most probably in future releases of FreeNAS it will be removed
 #include <net/if.h>
 #include <ifaddrs.h>
 // NEEDED BY do_tcp...
 #include <netinet/icmp6.h>
 // NEEDED BY do_space, do_inodes
 #include <sys/mount.h>
+// NEEDED BY do_uptime
+#include <time.h>
 
 #define KILO_FACTOR 1024
 #define MEGA_FACTOR 1048576     // 1024 * 1024
 #define GIGA_FACTOR 1073741824  // 1024 * 1024 * 1024
 
+#define MAX_INT_DIGITS 10 // maximum number of digits for int
+
 // NEEDED BY: do_disk_io
 #define RRD_TYPE_DISK "disk"
 
@@ -51,8 +54,6 @@
 #define IFA_DATA(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s)
 
 int do_freebsd_sysctl(int update_every, usec_t dt) {
-    (void)dt;
-
     static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1,
         do_loadavg = -1, do_all_processes = -1, do_disk_io = -1, do_swap = -1, do_ram = -1, do_swapio = -1,
         do_pgfaults = -1, do_committed = -1, do_ipc_semaphores = -1, do_ipc_shared_mem = -1, do_ipc_msg_queues = -1,
@@ -63,7 +64,7 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
         do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1,
         do_ip6_packets = -1, do_ip6_fragsout = -1, do_ip6_fragsin = -1, do_ip6_errors = -1,
         do_icmp6 = -1, do_icmp6_redir = -1, do_icmp6_errors = -1, do_icmp6_echos = -1, do_icmp6_router = -1,
-        do_icmp6_neighbor = -1, do_icmp6_types = -1, do_space = -1, do_inodes = -1;
+        do_icmp6_neighbor = -1, do_icmp6_types = -1, do_space = -1, do_inodes = -1, do_uptime = -1;
 
     if (unlikely(do_cpu == -1)) {
         do_cpu                  = config_get_boolean("plugin:freebsd:sysctl", "cpu utilization", 1);
@@ -98,6 +99,8 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
         do_tcpext_connaborts    = config_get_boolean_ondemand("plugin:freebsd:sysctl", "TCP connection aborts", CONFIG_ONDEMAND_ONDEMAND);
         do_udp_packets          = config_get_boolean("plugin:freebsd:sysctl", "ipv4 UDP packets", 1);
         do_udp_errors           = config_get_boolean("plugin:freebsd:sysctl", "ipv4 UDP errors", 1);
+        do_icmp_packets         = config_get_boolean("plugin:freebsd:sysctl", "ipv4 ICMP packets", 1);
+        do_icmpmsg              = config_get_boolean("plugin:freebsd:sysctl", "ipv4 ICMP messages", 1);
         do_ip_packets           = config_get_boolean("plugin:freebsd:sysctl", "ipv4 packets", 1);
         do_ip_fragsout          = config_get_boolean("plugin:freebsd:sysctl", "ipv4 fragments sent", 1);
         do_ip_fragsin           = config_get_boolean("plugin:freebsd:sysctl", "ipv4 fragments assembly", 1);
@@ -115,6 +118,7 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
         do_icmp6_types          = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp types", CONFIG_ONDEMAND_ONDEMAND);
         do_space                = config_get_boolean("plugin:freebsd:sysctl", "space usage for all disks", 1);
         do_inodes               = config_get_boolean("plugin:freebsd:sysctl", "inodes usage for all disks", 1);
+        do_uptime               = config_get_boolean("plugin:freebsd:sysctl", "system uptime", 1);
     }
 
     RRDSET *st;
@@ -128,7 +132,7 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
     char title[4096 + 1];
 
     // NEEDED BY: do_loadavg
-    static usec_t last_loadavg_usec = 0;
+    static usec_t next_loadavg_dt = 0;
     struct loadavg sysload;
 
     // NEEDED BY: do_cpu, do_cpu_cores
@@ -139,7 +143,7 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
 
     // NEEDED BY: do_cpu_cores
     static long *pcpu_cp_time = NULL;
-    char cpuid[8]; // no more than 4 digits expected
+    char cpuid[MAX_INT_DIGITS + 1];
 
     // NEEDED BY: do_all_processes, do_processes
     struct vmtotal vmtotal_data;
@@ -159,6 +163,7 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
     int numdevs;
     static void *devstat_data = NULL;
     struct devstat *dstat;
+    char disk[DEVSTAT_NAME_LEN + MAX_INT_DIGITS + 1];
     struct cur_dstat {
         collected_number duration_read_ms;
         collected_number duration_write_ms;
@@ -268,9 +273,12 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
     int mntsize;
     char mntonname[MNAMELEN + 1];
 
+    // NEEDED BY: do_uptime
+    struct timespec boot_time, cur_time;
+
     // --------------------------------------------------------------------
 
-    if (last_loadavg_usec <= dt) {
+    if (next_loadavg_dt <= dt) {
         if (likely(do_loadavg)) {
             if (unlikely(GETSYSCTL("vm.loadavg", sysload))) {
                 do_loadavg = 0;
@@ -290,12 +298,12 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
                 rrddim_set(st, "load5", (collected_number) ((double)sysload.ldavg[1] / sysload.fscale * 1000));
                 rrddim_set(st, "load15", (collected_number) ((double)sysload.ldavg[2] / sysload.fscale * 1000));
                 rrdset_done(st);
+
+                next_loadavg_dt = st->update_every * USEC_PER_SEC;
             }
         }
-
-        last_loadavg_usec = st->update_every * USEC_PER_SEC;
     }
-    else last_loadavg_usec -= dt;
+    else next_loadavg_dt -= dt;
 
     // --------------------------------------------------------------------
 
@@ -406,40 +414,33 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
                 error("DISABLED: cpu.cpuXX");
             } else {
                 pcpu_cp_time = reallocz(pcpu_cp_time, sizeof(cp_time) * ncpus);
-
-                for (i = 0; i < ncpus; i++) {
-                    if (unlikely(getsysctl("kern.cp_times", pcpu_cp_time, sizeof(cp_time) * ncpus))) {
-                        do_cpu_cores = 0;
-                        error("DISABLED: cpu.cpuXX");
-                        break;
-                    }
-                    if (unlikely(ncpus > 9999)) {
-                        error("FREEBSD: There are more than 4 digits in cpu cores number");
-                        do_cpu_cores = 0;
-                        error("DISABLED: cpu.cpuXX");
-                        break;
-                    }
-                    snprintfz(cpuid, 8, "cpu%d", i);
-
-                    st = rrdset_find_bytype("cpu", cpuid);
-                    if (unlikely(!st)) {
-                        st = rrdset_create("cpu", cpuid, NULL, "utilization", "cpu.cpu", "Core utilization", "percentage", 1000, update_every, RRDSET_TYPE_STACKED);
-
-                        rrddim_add(st, "user", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                        rrddim_add(st, "nice", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                        rrddim_add(st, "system", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                        rrddim_add(st, "interrupt", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                        rrddim_add(st, "idle", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                        rrddim_hide(st, "idle");
-                    }
-                    else rrdset_next(st);
-
-                    rrddim_set(st, "user", pcpu_cp_time[i * 5 + 0]);
-                    rrddim_set(st, "nice", pcpu_cp_time[i * 5 + 1]);
-                    rrddim_set(st, "system", pcpu_cp_time[i * 5 + 2]);
-                    rrddim_set(st, "interrupt", pcpu_cp_time[i * 5 + 3]);
-                    rrddim_set(st, "idle", pcpu_cp_time[i * 5 + 4]);
-                    rrdset_done(st);
+                if (unlikely(getsysctl("kern.cp_times", pcpu_cp_time, sizeof(cp_time) * ncpus))) {
+                    do_cpu_cores = 0;
+                    error("DISABLED: cpu.cpuXX");
+                } else {
+                    for (i = 0; i < ncpus; i++) {
+                        snprintfz(cpuid, MAX_INT_DIGITS, "cpu%d", i);
+                        st = rrdset_find_bytype("cpu", cpuid);
+                        if (unlikely(!st)) {
+                            st = rrdset_create("cpu", cpuid, NULL, "utilization", "cpu.cpu", "Core utilization",
+                                               "percentage", 1000, update_every, RRDSET_TYPE_STACKED);
+
+                            rrddim_add(st, "user", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                            rrddim_add(st, "nice", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                            rrddim_add(st, "system", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                            rrddim_add(st, "interrupt", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                            rrddim_add(st, "idle", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                            rrddim_hide(st, "idle");
+                        } else
+                            rrdset_next(st);
+
+                        rrddim_set(st, "user", pcpu_cp_time[i * 5 + 0]);
+                        rrddim_set(st, "nice", pcpu_cp_time[i * 5 + 1]);
+                        rrddim_set(st, "system", pcpu_cp_time[i * 5 + 2]);
+                        rrddim_set(st, "interrupt", pcpu_cp_time[i * 5 + 3]);
+                        rrddim_set(st, "idle", pcpu_cp_time[i * 5 + 4]);
+                        rrdset_done(st);
+                }
                 }
             }
         }
@@ -602,34 +603,35 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
                 error("DISABLED: disk.io");
             } else {
                 dstat = devstat_data + sizeof(long); // skip generation number
-                collected_number total_disk_reads = 0;
-                collected_number total_disk_writes = 0;
+                collected_number total_disk_kbytes_read = 0;
+                collected_number total_disk_kbytes_write = 0;
 
                 for (i = 0; i < numdevs; i++) {
                     if (((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) || ((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) {
+                        sprintf(disk, "%s%d", dstat[i].device_name, dstat[i].unit_number);
 
                         // --------------------------------------------------------------------
 
-                        st = rrdset_find_bytype(RRD_TYPE_DISK, dstat[i].device_name);
+                        st = rrdset_find_bytype(RRD_TYPE_DISK, disk);
                         if (unlikely(!st)) {
-                            st = rrdset_create(RRD_TYPE_DISK, dstat[i].device_name, NULL, dstat[i].device_name, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
+                            st = rrdset_create(RRD_TYPE_DISK, disk, NULL, disk, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
 
                             rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_INCREMENTAL);
                             rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_INCREMENTAL);
                         }
                         else rrdset_next(st);
 
-                        total_disk_reads += dstat[i].bytes[DEVSTAT_READ];
-                        total_disk_writes += dstat[i].bytes[DEVSTAT_WRITE];
+                        total_disk_kbytes_read += dstat[i].bytes[DEVSTAT_READ]/KILO_FACTOR;
+                        total_disk_kbytes_write += dstat[i].bytes[DEVSTAT_WRITE]/KILO_FACTOR;
                         prev_dstat.bytes_read = rrddim_set(st, "reads", dstat[i].bytes[DEVSTAT_READ]);
                         prev_dstat.bytes_write = rrddim_set(st, "writes", dstat[i].bytes[DEVSTAT_WRITE]);
                         rrdset_done(st);
 
                         // --------------------------------------------------------------------
 
-                        st = rrdset_find_bytype("disk_ops", dstat[i].device_name);
+                        st = rrdset_find_bytype("disk_ops", disk);
                         if (unlikely(!st)) {
-                            st = rrdset_create("disk_ops", dstat[i].device_name, NULL, dstat[i].device_name, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
+                            st = rrdset_create("disk_ops", disk, NULL, disk, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
                             st->isdetail = 1;
 
                             rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
@@ -643,9 +645,9 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
 
                         // --------------------------------------------------------------------
 
-                        st = rrdset_find_bytype("disk_qops", dstat[i].device_name);
+                        st = rrdset_find_bytype("disk_qops", disk);
                         if (unlikely(!st)) {
-                            st = rrdset_create("disk_qops", dstat[i].device_name, NULL, dstat[i].device_name, "disk.qops", "Disk Current I/O Operations", "operations", 2002, update_every, RRDSET_TYPE_LINE);
+                            st = rrdset_create("disk_qops", disk, NULL, disk, "disk.qops", "Disk Current I/O Operations", "operations", 2002, update_every, RRDSET_TYPE_LINE);
                             st->isdetail = 1;
 
                             rrddim_add(st, "operations", NULL, 1, 1, RRDDIM_ABSOLUTE);
@@ -657,9 +659,9 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
 
                         // --------------------------------------------------------------------
 
-                        st = rrdset_find_bytype("disk_util", dstat[i].device_name);
+                        st = rrdset_find_bytype("disk_util", disk);
                         if (unlikely(!st)) {
-                            st = rrdset_create("disk_util", dstat[i].device_name, NULL, dstat[i].device_name, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
+                            st = rrdset_create("disk_util", disk, NULL, disk, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
                             st->isdetail = 1;
 
                             rrddim_add(st, "utilization", NULL, 1, 10, RRDDIM_INCREMENTAL);
@@ -672,9 +674,9 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
 
                         // --------------------------------------------------------------------
 
-                        st = rrdset_find_bytype("disk_iotime", dstat[i].device_name);
+                        st = rrdset_find_bytype("disk_iotime", disk);
                         if (unlikely(!st)) {
-                            st = rrdset_create("disk_iotime", dstat[i].device_name, NULL, dstat[i].device_name, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
+                            st = rrdset_create("disk_iotime", disk, NULL, disk, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
                             st->isdetail = 1;
 
                             rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
@@ -696,9 +698,9 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
 
                             // --------------------------------------------------------------------
 
-                            st = rrdset_find_bytype("disk_await", dstat[i].device_name);
+                            st = rrdset_find_bytype("disk_await", disk);
                             if (unlikely(!st)) {
-                                st = rrdset_create("disk_await", dstat[i].device_name, NULL, dstat[i].device_name, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
+                                st = rrdset_create("disk_await", disk, NULL, disk, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
                                 st->isdetail = 1;
 
                                 rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_ABSOLUTE);
@@ -714,9 +716,9 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
 
                             // --------------------------------------------------------------------
 
-                            st = rrdset_find_bytype("disk_avgsz", dstat[i].device_name);
+                            st = rrdset_find_bytype("disk_avgsz", disk);
                             if (unlikely(!st)) {
-                                st = rrdset_create("disk_avgsz", dstat[i].device_name, NULL, dstat[i].device_name, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
+                                st = rrdset_create("disk_avgsz", disk, NULL, disk, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
                                 st->isdetail = 1;
 
                                 rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_ABSOLUTE);
@@ -732,9 +734,9 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
 
                             // --------------------------------------------------------------------
 
-                            st = rrdset_find_bytype("disk_svctm", dstat[i].device_name);
+                            st = rrdset_find_bytype("disk_svctm", disk);
                             if (unlikely(!st)) {
-                                st = rrdset_create("disk_svctm", dstat[i].device_name, NULL, dstat[i].device_name, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
+                                st = rrdset_create("disk_svctm", disk, NULL, disk, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
                                 st->isdetail = 1;
 
                                 rrddim_add(st, "svctm", NULL, 1, 1, RRDDIM_ABSOLUTE);
@@ -746,21 +748,21 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
                             rrdset_done(st);
                         }
                     }
+                }
 
-                    // --------------------------------------------------------------------
-
-                    st = rrdset_find_bytype("system", "io");
-                    if (unlikely(!st)) {
-                        st = rrdset_create("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA);
-                        rrddim_add(st, "in",  NULL,  1, 1024, RRDDIM_INCREMENTAL);
-                        rrddim_add(st, "out", NULL, -1, 1024, RRDDIM_INCREMENTAL);
-                    }
-                    else rrdset_next(st);
+                // --------------------------------------------------------------------
 
-                    rrddim_set(st, "in", total_disk_reads);
-                    rrddim_set(st, "out", total_disk_writes);
-                    rrdset_done(st);
+                st = rrdset_find_bytype("system", "io");
+                if (unlikely(!st)) {
+                    st = rrdset_create("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA);
+                    rrddim_add(st, "in",  NULL,  1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "out", NULL, -1, 1, RRDDIM_INCREMENTAL);
                 }
+                else rrdset_next(st);
+
+                rrddim_set(st, "in", total_disk_kbytes_read);
+                rrddim_set(st, "out", total_disk_kbytes_write);
+                rrdset_done(st);
             }
         }
     }
@@ -819,7 +821,9 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
         if (unlikely(GETSYSCTL("vm.stats.vm.v_active_count",    vmmeter_data.v_active_count) ||
                      GETSYSCTL("vm.stats.vm.v_inactive_count",  vmmeter_data.v_inactive_count) ||
                      GETSYSCTL("vm.stats.vm.v_wire_count",      vmmeter_data.v_wire_count) ||
+#if __FreeBSD_version < 1200016
                      GETSYSCTL("vm.stats.vm.v_cache_count",     vmmeter_data.v_cache_count) ||
+#endif
                      GETSYSCTL("vfs.bufspace",                  vfs_bufspace_count) ||
                      GETSYSCTL("vm.stats.vm.v_free_count",      vmmeter_data.v_free_count))) {
             do_ram = 0;
@@ -832,7 +836,9 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
                 rrddim_add(st, "active",    NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
                 rrddim_add(st, "inactive",  NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
                 rrddim_add(st, "wired",     NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
+#if __FreeBSD_version < 1200016
                 rrddim_add(st, "cache",     NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
+#endif
                 rrddim_add(st, "buffers",   NULL, 1, MEGA_FACTOR, RRDDIM_ABSOLUTE);
                 rrddim_add(st, "free",      NULL, system_pagesize, MEGA_FACTOR, RRDDIM_ABSOLUTE);
             }
@@ -841,7 +847,9 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
             rrddim_set(st, "active",    vmmeter_data.v_active_count);
             rrddim_set(st, "inactive",  vmmeter_data.v_inactive_count);
             rrddim_set(st, "wired",     vmmeter_data.v_wire_count);
+#if __FreeBSD_version < 1200016
             rrddim_set(st, "cache",     vmmeter_data.v_cache_count);
+#endif
             rrddim_set(st, "buffers",   vfs_bufspace_count);
             rrddim_set(st, "free",      vmmeter_data.v_free_count);
             rrdset_done(st);
@@ -1071,9 +1079,6 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
     if (likely(do_netisr || do_netisr_per_core)) {
         if (unlikely(GETSYSCTL("kern.smp.cpus", ncpus))) {
             common_error = 1;
-        } else if (unlikely(ncpus > 9999)) {
-            error("FREEBSD: There are more than 4 digits in cpu cores number");
-            common_error = 1;
         } else if (unlikely(sysctlbyname("net.isr.workstream", NULL, &netisr_workstream_size, NULL, 0) == -1)) {
             error("FREEBSD: sysctl(net.isr.workstream...) failed: %s", strerror(errno));
             common_error = 1;
@@ -1280,14 +1285,14 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
                     st->isdetail = 1;
 
                     rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
-#ifdef __IFI_OQDROPS
+#if __FreeBSD__ >= 11
                     rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
 #endif
                 }
                 else rrdset_next(st);
 
                 rrddim_set(st, "inbound", IFA_DATA(iqdrops));
-#ifdef __IFI_OQDROPS
+#if __FreeBSD__ >= 11
                 rrddim_set(st, "outbound", IFA_DATA(oqdrops));
 #endif
                 rrdset_done(st);
@@ -2173,5 +2178,26 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
         }
     }
 
+    // --------------------------------------------------------------------
+
+    if (likely(do_uptime)) {
+        if (unlikely(GETSYSCTL("kern.boottime", boot_time))) {
+            do_uptime = 0;
+            error("DISABLED: system.uptime");
+        } else {
+            clock_gettime(CLOCK_REALTIME, &cur_time);
+            st = rrdset_find("system.uptime");
+
+            if(unlikely(!st)) {
+                st = rrdset_create("system", "uptime", NULL, "uptime", NULL, "System Uptime", "seconds", 1000, update_every, RRDSET_TYPE_LINE);
+                rrddim_add(st, "uptime", NULL, 1, 1, RRDDIM_ABSOLUTE);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "uptime", cur_time.tv_sec - boot_time.tv_sec);
+            rrdset_done(st);
+        }
+    }
+
     return 0;
 }