Static neighbor support

This changes adds support for assigning static ARP / NDP
neighbors on each ethernet interface.

Tested:
    Ran inside a romulus VM and made sure that `ip neigh add`
    commands triggered the refresh of static_neighbor objects.
    Also verified that static neighbors could be added through
    the CreateStatic dbus interface. Verified that deleting those
    static entries would persist to the system.

Change-Id: Ifaf753525c532b6dade392d7eb4ebd6d7242d480
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/rtnetlink_server.cpp b/rtnetlink_server.cpp
index 732055a..1c4fd53 100644
--- a/rtnetlink_server.cpp
+++ b/rtnetlink_server.cpp
@@ -14,6 +14,7 @@
 #include <memory>
 #include <phosphor-logging/elog-errors.hpp>
 #include <phosphor-logging/log.hpp>
+#include <string_view>
 #include <xyz/openbmc_project/Common/error.hpp>
 
 namespace phosphor
@@ -26,7 +27,7 @@
 namespace rtnetlink
 {
 
-static bool shouldRefresh(const struct nlmsghdr& hdr)
+static bool shouldRefresh(const struct nlmsghdr& hdr, std::string_view data)
 {
     switch (hdr.nlmsg_type)
     {
@@ -37,6 +38,18 @@
         {
             return true;
         }
+        case RTM_NEWNEIGH:
+        case RTM_DELNEIGH:
+        {
+            struct ndmsg ndm;
+            if (data.size() < sizeof(ndm))
+            {
+                return false;
+            }
+            memcpy(&ndm, data.data(), sizeof(ndm));
+            // We only want to refresh for static neighbors
+            return ndm.ndm_state & NUD_PERMANENT;
+        }
     }
 
     return false;
@@ -57,7 +70,10 @@
                (netLinkHeader->nlmsg_type != NLMSG_DONE);
              netLinkHeader = NLMSG_NEXT(netLinkHeader, len))
         {
-            if (shouldRefresh(*netLinkHeader))
+            std::string_view data(
+                reinterpret_cast<const char*>(NLMSG_DATA(netLinkHeader)),
+                netLinkHeader->nlmsg_len - NLMSG_HDRLEN);
+            if (shouldRefresh(*netLinkHeader, data))
             {
                 // starting the timer here to make sure that we don't want
                 // create the child objects multiple times.
@@ -125,7 +141,7 @@
     std::memset(&addr, 0, sizeof(addr));
     addr.nl_family = AF_NETLINK;
     addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR |
-                     RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE;
+                     RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NEIGH;
 
     if (bind(smartSock(), (struct sockaddr*)&addr, sizeof(addr)) < 0)
     {