system_queries: Add netlink based delete

We shouldn't depend on calling the IP binary

Change-Id: I4e9b3229ef936dad96e2fcfcea8f6b32a9c9f801
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/ethernet_interface.cpp b/src/ethernet_interface.cpp
index b57a24f..f480b2f 100644
--- a/src/ethernet_interface.cpp
+++ b/src/ethernet_interface.cpp
@@ -897,11 +897,11 @@
         }
     }
 
-    // We need to forcibly delete the interface as systemd does not
-    deleteInterface(intf);
-
     if (eth.ifIdx > 0)
     {
+        // We need to forcibly delete the interface as systemd does not
+        system::deleteIntf(eth.ifIdx);
+
         eth.manager.interfacesByIdx.erase(eth.ifIdx);
     }
     eth.manager.interfaces.erase(intf);
diff --git a/src/system_queries.cpp b/src/system_queries.cpp
index 9a360bd..9a8cba8 100644
--- a/src/system_queries.cpp
+++ b/src/system_queries.cpp
@@ -1,7 +1,10 @@
 #include "system_queries.hpp"
 
+#include "netlink.hpp"
+
 #include <fmt/format.h>
 #include <linux/ethtool.h>
+#include <linux/rtnetlink.h>
 #include <linux/sockios.h>
 #include <net/if.h>
 
@@ -109,4 +112,26 @@
     getIFSock().ioctl(SIOCSIFFLAGS, &ifr);
 }
 
+void deleteIntf(unsigned idx)
+{
+    if (idx == 0)
+    {
+        return;
+    }
+    ifinfomsg msg = {};
+    msg.ifi_family = AF_UNSPEC;
+    msg.ifi_index = idx;
+    netlink::performRequest(
+        NETLINK_ROUTE, RTM_DELLINK, NLM_F_REPLACE, msg,
+        [&](const nlmsghdr& hdr, std::string_view data) {
+            int err = 0;
+            if (hdr.nlmsg_type == NLMSG_ERROR)
+            {
+                err = netlink::extractRtData<nlmsgerr>(data).error;
+            }
+            throw std::runtime_error(
+                fmt::format("Failed to delete `{}`: {}", idx, strerror(err)));
+        });
+}
+
 } // namespace phosphor::network::system
diff --git a/src/system_queries.hpp b/src/system_queries.hpp
index 4c187c7..9027cb3 100644
--- a/src/system_queries.hpp
+++ b/src/system_queries.hpp
@@ -18,4 +18,6 @@
 
 void setNICUp(std::string_view ifname, bool up);
 
+void deleteIntf(unsigned idx);
+
 } // namespace phosphor::network::system
diff --git a/src/util.cpp b/src/util.cpp
index 5df9afa..938e4d4 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -129,47 +129,6 @@
 
 } // namespace internal
 
-void deleteInterface(stdplus::const_zstring intf)
-{
-    pid_t pid = fork();
-    int status{};
-
-    if (pid == 0)
-    {
-
-        execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
-        auto error = errno;
-        log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
-                        entry("INTF=%s", intf.c_str()));
-        elog<InternalFailure>();
-    }
-    else if (pid < 0)
-    {
-        auto error = errno;
-        log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
-        elog<InternalFailure>();
-    }
-    else if (pid > 0)
-    {
-        while (waitpid(pid, &status, 0) == -1)
-        {
-            if (errno != EINTR)
-            { /* Error other than EINTR */
-                status = -1;
-                break;
-            }
-        }
-
-        if (status < 0)
-        {
-            log<level::ERR>("Unable to delete the interface",
-                            entry("INTF=%s", intf.c_str()),
-                            entry("STATUS=%d", status));
-            elog<InternalFailure>();
-        }
-    }
-}
-
 std::optional<std::string> interfaceToUbootEthAddr(std::string_view intf)
 {
     constexpr auto pfx = "eth"sv;
diff --git a/src/util.hpp b/src/util.hpp
index 3638160..4cf27a0 100644
--- a/src/util.hpp
+++ b/src/util.hpp
@@ -74,11 +74,6 @@
     throw std::invalid_argument("Unrecognized family");
 }
 
-/** @brief Delete the given interface.
- *  @param[in] intf - interface name.
- */
-void deleteInterface(stdplus::const_zstring intf);
-
 /** @brief Converts the interface name into a u-boot environment
  *         variable that would hold its ethernet address.
  *