system: Get current neighbours from Rtnetlink

This will be used for implementing neighbours in ietf-ip YANG model [1].

We wrap libnl's rtnl_link and rtnl_neigh objects into unique_ptr with
custom deleter so the lifetime is auto-managed.

[1] https://tools.ietf.org/html/rfc8344

Change-Id: I1497d9f00d3e8ce969edb630024e26487ee7d0f4
diff --git a/src/system/Rtnetlink.cpp b/src/system/Rtnetlink.cpp
index 476a216..5201b62 100644
--- a/src/system/Rtnetlink.cpp
+++ b/src/system/Rtnetlink.cpp
@@ -6,6 +6,7 @@
  */
 
 #include <netlink/route/link.h>
+#include <netlink/route/neighbour.h>
 #include <utility>
 #include "Rtnetlink.h"
 #include "utils/log.h"
@@ -155,11 +156,23 @@
 
     {
         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);
     }
+
+    {
+        nl_cache* tmpCache;
+
+        if (auto err = rtnl_neigh_alloc_cache(m_nlSocket.get(), &tmpCache); err < 0) {
+            throw RtnetlinkException("rtnl_neigh_alloc_cache", err);
+        }
+
+        m_nlCacheNeighbour = nlCache(tmpCache, nl_cache_free);
+    }
 }
 
 Rtnetlink::~Rtnetlink() = default;
@@ -176,9 +189,23 @@
     return res;
 }
 
+std::vector<std::pair<Rtnetlink::nlNeigh, Rtnetlink::nlLink>> Rtnetlink::getNeighbours()
+{
+    resyncCache(m_nlCacheLink);
+    resyncCache(m_nlCacheNeighbour);
+
+    std::vector<std::pair<Rtnetlink::nlNeigh, Rtnetlink::nlLink>> res;
+    nlCacheForeachWrapper<rtnl_neigh>(m_nlCacheNeighbour.get(), [this, &res](rtnl_neigh* neigh) {
+        auto link = rtnl_link_get(m_nlCacheLink.get(), rtnl_neigh_get_ifindex(neigh));
+
+        res.emplace_back(nlObjectWrap(nlObjectClone(neigh)), nlObjectWrap(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 4ee1659..df73680 100644
--- a/src/system/Rtnetlink.h
+++ b/src/system/Rtnetlink.h
@@ -29,6 +29,7 @@
     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 nlNeigh = std::unique_ptr<rtnl_neigh, std::function<void(rtnl_neigh*)>>;
 
     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_*
@@ -36,6 +37,7 @@
     Rtnetlink(LinkCB cbLink, AddrCB cbAddr);
     ~Rtnetlink();
     std::vector<nlLink> getLinks();
+    std::vector<std::pair<nlNeigh, nlLink>> getNeighbours();
 
 private:
     void resyncCache(const nlCache& cache);
@@ -43,7 +45,8 @@
     velia::Log m_log;
     std::unique_ptr<nl_sock, std::function<void(nl_sock*)>> m_nlSocket;
     nlCacheManager m_nlCacheManager; // for updates
-    nlCache m_nlCacheLink; // for getLinks
+    nlCache m_nlCacheLink; // for getLinks, getNeighbours
+    nlCache m_nlCacheNeighbour; // for getNeighbours
     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