network_manager: Absorb all state change functions

We are going to need to keep track of more state for when interfaces are
not yet set up. It also  makes testing easier if we can keep the
rtnetlink_server as simple as possible.

Change-Id: Iad94bf609feeb96a78f1c4ec3313c4f638eda951
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/network_manager.cpp b/src/network_manager.cpp
index f862e28..5f80154 100644
--- a/src/network_manager.cpp
+++ b/src/network_manager.cpp
@@ -138,6 +138,99 @@
     interfacesByIdx.emplace(info.idx, ptr);
 }
 
+inline void getIntfOrLog(const decltype(Manager::interfacesByIdx)& intfs,
+                         unsigned idx, auto&& cb)
+{
+    auto it = intfs.find(idx);
+    if (it == intfs.end())
+    {
+        auto msg = fmt::format("Interface `{}` not found", idx);
+        log<level::ERR>(msg.c_str(), entry("IFIDX=%u", idx));
+        return;
+    }
+    cb(*it->second);
+}
+
+void Manager::addAddress(const AddressInfo& info)
+{
+    getIntfOrLog(interfacesByIdx, info.ifidx,
+                 [&](auto& intf) { intf.addAddr(info); });
+}
+
+void Manager::removeAddress(const AddressInfo& info)
+{
+    getIntfOrLog(interfacesByIdx, info.ifidx,
+                 [&](auto& intf) { intf.addrs.erase(info.ifaddr); });
+}
+
+void Manager::addNeighbor(const NeighborInfo& info)
+{
+    getIntfOrLog(interfacesByIdx, info.ifidx,
+                 [&](auto& intf) { intf.addStaticNeigh(info); });
+}
+
+void Manager::removeNeighbor(const NeighborInfo& info)
+{
+    if (info.addr)
+    {
+        getIntfOrLog(interfacesByIdx, info.ifidx, [&](auto& intf) {
+            intf.staticNeighbors.erase(*info.addr);
+        });
+    }
+}
+
+void Manager::addDefGw(unsigned ifidx, InAddrAny addr)
+{
+    getIntfOrLog(interfacesByIdx, ifidx, [&](auto& intf) {
+        std::visit(
+            [&](auto addr) {
+                if constexpr (std::is_same_v<in_addr, decltype(addr)>)
+                {
+                    intf.EthernetInterfaceIntf::defaultGateway(
+                        std::to_string(addr));
+                }
+                else if constexpr (std::is_same_v<in6_addr, decltype(addr)>)
+                {
+                    intf.EthernetInterfaceIntf::defaultGateway6(
+                        std::to_string(addr));
+                }
+                else
+                {
+                    static_assert(!std::is_same_v<void, decltype(addr)>);
+                }
+            },
+            addr);
+    });
+}
+
+void Manager::removeDefGw(unsigned ifidx, InAddrAny addr)
+{
+    getIntfOrLog(interfacesByIdx, ifidx, [&](auto& intf) {
+        std::visit(
+            [&](auto addr) {
+                if constexpr (std::is_same_v<in_addr, decltype(addr)>)
+                {
+                    if (intf.defaultGateway() == std::to_string(addr))
+                    {
+                        intf.EthernetInterfaceIntf::defaultGateway("");
+                    }
+                }
+                else if constexpr (std::is_same_v<in6_addr, decltype(addr)>)
+                {
+                    if (intf.defaultGateway6() == std::to_string(addr))
+                    {
+                        intf.EthernetInterfaceIntf::defaultGateway6("");
+                    }
+                }
+                else
+                {
+                    static_assert(!std::is_same_v<void, decltype(addr)>);
+                }
+            },
+            addr);
+    });
+}
+
 void Manager::createInterfaces()
 {
     // clear all the interfaces first
diff --git a/src/network_manager.hpp b/src/network_manager.hpp
index f7eb6bd..1b61b3b 100644
--- a/src/network_manager.hpp
+++ b/src/network_manager.hpp
@@ -66,6 +66,18 @@
     /** @brief Adds a single interface to the interface map */
     void addInterface(InterfaceInfo& info, bool enabled);
 
+    /** @brief Add / remove an address to the interface or queue */
+    void addAddress(const AddressInfo& info);
+    void removeAddress(const AddressInfo& info);
+
+    /** @brief Add / remove a neighbor to the interface or queue */
+    void addNeighbor(const NeighborInfo& info);
+    void removeNeighbor(const NeighborInfo& info);
+
+    /** @brief Add / remove default gateway for interface */
+    void addDefGw(unsigned ifidx, InAddrAny addr);
+    void removeDefGw(unsigned ifidx, InAddrAny addr);
+
     /** @brief Fetch the interface and the ipaddress details
      *         from the system and create the ethernet interraces
      *         dbus object.
diff --git a/src/rtnetlink_server.cpp b/src/rtnetlink_server.cpp
index 5afe637..2f2a152 100644
--- a/src/rtnetlink_server.cpp
+++ b/src/rtnetlink_server.cpp
@@ -40,93 +40,14 @@
     return false;
 }
 
-static void rthandler(Manager& m, bool n, std::string_view data)
+inline void rthandler(std::string_view data, auto&& cb)
 {
-    auto ret = netlink::gatewayFromRtm(data);
+    auto ret = gatewayFromRtm(data);
     if (!ret)
     {
         return;
     }
-    auto ifIdx = std::get<unsigned>(*ret);
-    auto it = m.interfacesByIdx.find(ifIdx);
-    if (it == m.interfacesByIdx.end())
-    {
-        auto msg = fmt::format("Interface `{}` not found for route", ifIdx);
-        log<level::ERR>(msg.c_str(), entry("IFIDX=%u", ifIdx));
-        return;
-    }
-    std::visit(
-        [&](auto addr) {
-            if constexpr (std::is_same_v<in_addr, decltype(addr)>)
-            {
-                if (n)
-                {
-                    it->second->EthernetInterfaceIntf::defaultGateway(
-                        std::to_string(addr));
-                }
-                else if (it->second->defaultGateway() == std::to_string(addr))
-                {
-                    it->second->EthernetInterfaceIntf::defaultGateway("");
-                }
-            }
-            else if constexpr (std::is_same_v<in6_addr, decltype(addr)>)
-            {
-                if (n)
-                {
-                    it->second->EthernetInterfaceIntf::defaultGateway6(
-                        std::to_string(addr));
-                }
-                else if (it->second->defaultGateway6() == std::to_string(addr))
-                {
-                    it->second->EthernetInterfaceIntf::defaultGateway6("");
-                }
-            }
-            else
-            {
-                static_assert(!std::is_same_v<void, decltype(addr)>);
-            }
-        },
-        std::get<InAddrAny>(*ret));
-}
-
-static void addrhandler(Manager& m, bool n, std::string_view data)
-{
-    auto info = netlink::addrFromRtm(data);
-    auto it = m.interfacesByIdx.find(info.ifidx);
-    if (it == m.interfacesByIdx.end())
-    {
-        auto msg = fmt::format("Interface `{}` not found for addr", info.ifidx);
-        log<level::ERR>(msg.c_str(), entry("IFIDX=%u", info.ifidx));
-        return;
-    }
-    if (n)
-    {
-        it->second->addAddr(info);
-    }
-    else
-    {
-        it->second->addrs.erase(info.ifaddr);
-    }
-}
-
-static void neighhandler(Manager& m, bool n, std::string_view data)
-{
-    auto info = netlink::neighFromRtm(data);
-    auto it = m.interfacesByIdx.find(info.ifidx);
-    if (it == m.interfacesByIdx.end())
-    {
-        auto msg = fmt::format("Interface `{}` not found for addr", info.ifidx);
-        log<level::ERR>(msg.c_str(), entry("IFIDX=%u", info.ifidx));
-        return;
-    }
-    if (n)
-    {
-        it->second->addStaticNeigh(info);
-    }
-    else if (info.addr)
-    {
-        it->second->staticNeighbors.erase(*info.addr);
-    }
+    cb(std::get<unsigned>(*ret), std::get<InAddrAny>(*ret));
 }
 
 static void handler(Manager& m, const nlmsghdr& hdr, std::string_view data)
@@ -140,29 +61,33 @@
         switch (hdr.nlmsg_type)
         {
             case RTM_NEWROUTE:
-                rthandler(m, true, data);
+                rthandler(data, [&](auto ifidx, auto addr) {
+                    m.addDefGw(ifidx, addr);
+                });
                 break;
             case RTM_DELROUTE:
-                rthandler(m, false, data);
+                rthandler(data, [&](auto ifidx, auto addr) {
+                    m.removeDefGw(ifidx, addr);
+                });
                 break;
             case RTM_NEWADDR:
-                addrhandler(m, true, data);
+                m.addAddress(addrFromRtm(data));
                 break;
             case RTM_DELADDR:
-                addrhandler(m, false, data);
+                m.removeAddress(addrFromRtm(data));
                 break;
             case RTM_NEWNEIGH:
-                neighhandler(m, true, data);
+                m.addNeighbor(neighFromRtm(data));
                 break;
             case RTM_DELNEIGH:
-                neighhandler(m, false, data);
+                m.removeNeighbor(neighFromRtm(data));
                 break;
         }
     }
     catch (const std::exception& e)
     {
-        auto msg = fmt::format("Failed parsing netlink event: {}", e.what());
-        log<level::ERR>(msg.c_str());
+        auto msg = fmt::format("Failed handling netlink event: {}", e.what());
+        log<level::ERR>(msg.c_str(), entry("ERROR=%s", e.what()));
     }
 }