system: Get current links from Rtnetlink
This will be used for statistics retrieval (see next commits).
We wrap libnl's rtnl_link objects into unique_ptr with custom deleter
so the lifetime is auto-managed.
Change-Id: Ic2d14d19f3992ad68ae2df70f01c60f49bfea577
diff --git a/src/system/Rtnetlink.cpp b/src/system/Rtnetlink.cpp
index f99c62f..476a216 100644
--- a/src/system/Rtnetlink.cpp
+++ b/src/system/Rtnetlink.cpp
@@ -42,6 +42,19 @@
}
}
+/** @brief Wraps rtnl object with unique_ptr and adds an appropriate deleter. */
+template <class T>
+std::unique_ptr<T, std::function<void(T*)>> nlObjectWrap(T* obj)
+{
+ return std::unique_ptr<T, std::function<void(T*)>>(obj, [] (T* obj) { nl_object_put(OBJ_CAST(obj)); });
+}
+
+template <class T>
+T* nlObjectClone(T* obj)
+{
+ return reinterpret_cast<T*>(nl_object_clone(OBJ_CAST(obj)));
+}
+
}
namespace velia::system {
@@ -96,9 +109,18 @@
Rtnetlink::Rtnetlink(LinkCB cbLink, AddrCB cbAddr)
: m_log(spdlog::get("system"))
+ , m_nlSocket(nl_socket_alloc(), nl_socket_free)
, m_cbLink(std::move(cbLink))
, m_cbAddr(std::move(cbAddr))
{
+ if (!m_nlSocket) {
+ throw RtnetlinkException("nl_socket_alloc failed");
+ }
+
+ if (auto err = nl_connect(m_nlSocket.get(), NETLINK_ROUTE); err < 0) {
+ throw RtnetlinkException("nl_connect", err);
+ }
+
{
nl_cache_mngr* tmpManager;
if (auto err = nl_cache_mngr_alloc(nullptr /* alloc and manage new netlink socket */, NETLINK_ROUTE, NL_AUTO_PROVIDE, &tmpManager); err < 0) {
@@ -130,8 +152,33 @@
nlCacheForeachWrapper<rtnl_addr>(cacheRouteAddr, [this](rtnl_addr* addr) {
m_cbAddr(addr, NL_ACT_NEW);
});
+
+ {
+ nl_cache* tmpCache;
+ if (auto err = rtnl_link_alloc_cache(m_nlSocket.get(), AF_UNSPEC, &tmpCache); err < 0) {
+ throw RtnetlinkException("rtnl_link_alloc_cache", err);
+ }
+ m_nlCacheLink = nlCache(tmpCache, nl_cache_free);
+ }
}
Rtnetlink::~Rtnetlink() = default;
+std::vector<Rtnetlink::nlLink> Rtnetlink::getLinks()
+{
+ resyncCache(m_nlCacheLink);
+
+ std::vector<Rtnetlink::nlLink> res;
+ nlCacheForeachWrapper<rtnl_link>(m_nlCacheLink.get(), [&res](rtnl_link* link) {
+ res.emplace_back(nlObjectWrap(nlObjectClone(link)));
+ });
+
+ return res;
+}
+
+void Rtnetlink::resyncCache(const nlCache& cache)
+{
+ nl_cache_resync(m_nlSocket.get(), cache.get(), [](nl_cache*, nl_object*, int, void*){}, nullptr);
+}
+
}
diff --git a/src/system/Rtnetlink.h b/src/system/Rtnetlink.h
index 2cf007c..4ee1659 100644
--- a/src/system/Rtnetlink.h
+++ b/src/system/Rtnetlink.h
@@ -12,6 +12,7 @@
#include <netlink/netlink.h>
#include <netlink/route/addr.h>
#include <netlink/route/link.h>
+#include <netlink/route/neighbour.h>
#include <stdexcept>
#include <thread>
#include "utils/log-fwd.h"
@@ -26,15 +27,23 @@
class Rtnetlink {
public:
using nlCacheManager = std::shared_ptr<nl_cache_mngr>;
+ using nlCache = std::unique_ptr<nl_cache, std::function<void(nl_cache*)>>;
+ using nlLink = std::unique_ptr<rtnl_link, std::function<void(rtnl_link*)>>;
+
using LinkCB = std::function<void(rtnl_link* link, int cacheAction)>; /// cacheAction: NL_ACT_*
using AddrCB = std::function<void(rtnl_addr* addr, int cacheAction)>; /// cacheAction: NL_ACT_*
Rtnetlink(LinkCB cbLink, AddrCB cbAddr);
~Rtnetlink();
+ std::vector<nlLink> getLinks();
private:
+ void resyncCache(const nlCache& cache);
+
velia::Log m_log;
- nlCacheManager m_nlCacheManager;
+ std::unique_ptr<nl_sock, std::function<void(nl_sock*)>> m_nlSocket;
+ nlCacheManager m_nlCacheManager; // for updates
+ nlCache m_nlCacheLink; // for getLinks
LinkCB m_cbLink;
AddrCB m_cbAddr;
std::unique_ptr<impl::nlCacheMngrWatcher> m_nlCacheMngrWatcher; // first to destroy, because the thread uses m_nlCacheManager and m_log