--- plugins/network/CMakeLists.txt
+++ plugins/network/CMakeLists.txt
@@ -21,6 +21,11 @@ target_link_libraries(ksystemstats_plugin_network PRIVATE Qt::Core Qt::Gui Qt::D
 if (KF6NetworkManagerQt_FOUND)
     target_link_libraries(ksystemstats_plugin_network PRIVATE KF6::NetworkManagerQt)
 endif()
+
+if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
+    target_sources(ksystemstats_plugin_network PRIVATE SysctlBackend.cpp)
+endif()
+
 if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
     target_sources(ksystemstats_plugin_network PRIVATE RtNetlinkBackend.cpp)
     target_link_libraries(ksystemstats_plugin_network PRIVATE ${NL_LIBRARIES} Qt::Network)
--- plugins/network/NetworkPlugin.cpp
+++ plugins/network/NetworkPlugin.cpp
@@ -24,7 +24,9 @@
 #ifdef Q_OS_LINUX
 #include "RtNetlinkBackend.h"
 #endif
-
+#ifdef Q_OS_FREEBSD
+#include "SysctlBackend.h"
+#endif
 class NetworkPrivate
 {
 public:
@@ -52,6 +54,9 @@ NetworkPlugin::NetworkPlugin(QObject *parent, const QVariantList &args)
 #endif
 #ifdef Q_OS_LINUX
     backendFunctions.emplace_back([](NetworkPlugin *parent) -> NetworkBackend* {return new RtNetlinkBackend(parent);});
+#endif
+#ifdef Q_OS_FREEBSD
+    backendFunctions.emplace_back([](NetworkPlugin *parent) -> NetworkBackend* {return new SysctlBackend(parent);});
 #endif
     for (auto func : backendFunctions) {
         auto backend = func(this);
--- /dev/null
+++ plugins/network/SysctlBackend.cpp
@@ -0,0 +1,160 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Jesper Schmitz Mouridsen <jesper@schmitz.computer>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
+ */
+
+#include "SysctlBackend.h"
+#include <arpa/inet.h>
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <net/if_mib.h>
+#include <net/if_types.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <systemstats/SysFsSensor.h>
+
+SysctlNetDevice::SysctlNetDevice(const QString &id, const QString &name, int ifnumber)
+    : NetworkDevice(id, name)
+{
+    m_sysctlName = {CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_IFDATA, ifnumber, IFDATA_GENERAL};
+    // Even though we have no sensor, we need to have a name for the grouped text on the front page
+    // of plasma-systemmonitor
+    m_networkSensor->setValue(id);
+    std::array<KSysGuard::SensorProperty *, 6> statisticSensors =
+        {m_downloadSensor, m_downloadBitsSensor, m_totalDownloadSensor, m_uploadSensor, m_uploadBitsSensor, m_totalUploadSensor};
+    auto resetStatistics = [this, statisticSensors]() {
+        if (std::none_of(statisticSensors.begin(), statisticSensors.end(), [](auto property) {
+                return property->isSubscribed();
+            })) {
+            m_totalDownloadSensor->setValue(0);
+            m_totalUploadSensor->setValue(0);
+            m_statisticsTimer->stop();
+        } else if (!m_statisticsTimer->isActive()) {
+            m_statisticsTimer->start();
+        }
+    };
+    for (auto property : statisticSensors) {
+        connect(property, &KSysGuard::SensorProperty::subscribedChanged, this, resetStatistics);
+    }
+    m_statisticsTimer = std::make_unique<QTimer>();
+    m_statisticsTimer->setInterval(UpdateRate);
+    connect(m_statisticsTimer.get(), &QTimer::timeout, this, [this]() {
+        ifmibdata ifmd{};
+        size_t len = sizeof(ifmd);
+        if (sysctl(m_sysctlName.data(), 6, &ifmd, &len, NULL, 0) == 0) {
+            const qulonglong newDownload = ifmd.ifmd_data.ifi_ibytes;
+            const qulonglong previousDownload = m_totalDownloadSensor->value().toULongLong();
+            const qulonglong deltaDownload = newDownload - previousDownload;
+            if (previousDownload > 0) {
+                m_downloadSensor->setValue(deltaDownload * 1000 / UpdateRate);
+                m_downloadBitsSensor->setValue((deltaDownload * 1000 / UpdateRate) * 8);
+            }
+            m_totalDownloadSensor->setValue(newDownload);
+
+            const qulonglong newUpload = ifmd.ifmd_data.ifi_obytes;
+            const qulonglong previousUpload = m_totalUploadSensor->value().toULongLong();
+            const qulonglong deltaUpload = newUpload - previousUpload;
+            if (previousUpload > 0) {
+                m_uploadSensor->setValue(deltaUpload * 1000 / UpdateRate);
+                m_uploadBitsSensor->setValue((deltaUpload * 1000 / UpdateRate) * 8);
+            }
+            m_totalUploadSensor->setValue(newUpload);
+        }
+    });
+}
+void SysctlNetDevice::update()
+{
+    char addr_buf[NI_MAXHOST];
+    QStringList ipv4_addrs;
+    QStringList ipv6_addrs;
+    struct sockaddr_in *sin;
+
+    ipv4_addrs.clear();
+    ipv6_addrs.clear();
+    ifaddrs *ifap;
+    bzero(&ifap, sizeof(ifap));
+    for (getifaddrs(&ifap); ifap != nullptr; ifap = ifap->ifa_next) {
+        if (name() == QString::fromLatin1(ifap->ifa_name)) {
+            sin = reinterpret_cast<struct sockaddr_in *>(ifap->ifa_addr);
+            if (sin == NULL)
+                return;
+
+            if(getnameinfo(ifap->ifa_addr, sin->sin_len, addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST)==0) {
+
+	        if (sin->sin_family == AF_INET) {
+                    ipv4_addrs << QString::fromLatin1(addr_buf);
+		}
+                if (sin->sin_family == AF_INET6) {
+	            ipv6_addrs << QString::fromLatin1(addr_buf);
+                }
+	    }
+
+        }
+    }
+    m_ipv4Sensor->setValue(ipv4_addrs.join("\n"));
+    m_ipv6Sensor->setValue(ipv6_addrs.join("\n"));
+    freeifaddrs(ifap);
+}
+
+SysctlNetDevice::~SysctlNetDevice()
+{
+}
+SysctlBackend::SysctlBackend(QObject *parent)
+    : NetworkBackend(parent)
+{
+}
+
+SysctlBackend::~SysctlBackend()
+{
+    qDeleteAll(m_devices);
+}
+
+bool SysctlBackend::isSupported()
+{
+    return true;
+}
+
+void SysctlBackend::start()
+{
+    int count, i;
+    size_t len;
+    int ifcnt_name[] = {CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_SYSTEM, IFMIB_IFCOUNT};
+    len = sizeof(int);
+    if (sysctl(ifcnt_name, 5, &count, &len, NULL, 0) < 0) {
+        return;
+    }
+
+    for (i = 1; i <= count; i++) {
+        struct ifmibdata ifmd {
+        };
+        size_t len = sizeof(ifmd);
+        int sname[6] = {CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_IFDATA, i, IFDATA_GENERAL};
+
+        if (sysctl(sname, 6, &ifmd, &len, NULL, 0) < 0) {
+            continue;
+        }
+
+        if ((ifmd.ifmd_data.ifi_type == IFT_ETHER) || (ifmd.ifmd_data.ifi_type == IFT_IEEE80211)) {
+            auto device = new SysctlNetDevice(QString::fromLatin1(ifmd.ifmd_name), QString::fromLatin1(ifmd.ifmd_name), i);
+
+            m_devices.insert(QByteArray(ifmd.ifmd_name), device);
+            Q_EMIT deviceAdded(device);
+        }
+    }
+}
+
+void SysctlBackend::stop()
+{
+}
+
+void SysctlBackend::update()
+{
+    QHashIterator<QByteArray, SysctlNetDevice *> iter(m_devices);
+    while (iter.hasNext()) {
+        iter.next();
+        iter.value()->update();
+    }
+}
--- /dev/null
+++ plugins/network/SysctlBackend.h
@@ -0,0 +1,42 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Jesper Schmitz Mouridsen <jesper@schmitz.computer>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
+ */
+
+#pragma once
+
+#include "NetworkBackend.h"
+#include "NetworkDevice.h"
+#include <array>
+#include <QElapsedTimer>
+#include <QTimer>
+
+static const int UpdateRate = 500;
+class SysctlNetDevice : public NetworkDevice
+{
+    Q_OBJECT
+
+public:
+    SysctlNetDevice(const QString &id, const QString &name,int ifnumber);
+    ~SysctlNetDevice() override;
+    std::array<int,6> m_sysctlName;
+    void update();
+    bool isConnected() const;
+    std::unique_ptr<QTimer> m_statisticsTimer;
+    QList<struct sockaddr *> m_ifaddrs;
+};
+
+class SysctlBackend : public NetworkBackend
+{
+public:
+    SysctlBackend(QObject *parent);
+    ~SysctlBackend() override;
+    bool isSupported() override;
+    void start() override;
+    void stop() override;
+    void update() override;
+
+private:
+    QHash<QByteArray, SysctlNetDevice *> m_devices;
+};
