rtnetlink: Migrate IP functions

Change-Id: I4c87b59306911df4c5a73e441b2b962fbaab072c
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/test/meson.build b/test/meson.build
index 3f84156..6a46c1d 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -46,11 +46,11 @@
 tests = [
   'config_parser',
   'ethernet_interface',
-  'ipaddress',
   'neighbor',
   'netlink',
   'network_manager',
-  #'rtnetlink',
+  'rtnetlink',
+  #'rtnetlink_server',
   'system_queries',
   'types',
   'util',
diff --git a/test/test_ipaddress.cpp b/test/test_ipaddress.cpp
deleted file mode 100644
index 9747cf9..0000000
--- a/test/test_ipaddress.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-#include "ipaddress.hpp"
-#include "util.hpp"
-
-#include <arpa/inet.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-
-#include <cstring>
-#include <stdexcept>
-#include <string>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-namespace phosphor
-{
-namespace network
-{
-namespace detail
-{
-
-TEST(ParseAddress, NotAddressType)
-{
-    nlmsghdr hdr{};
-    hdr.nlmsg_type = RTM_NEWLINK;
-    AddressFilter filter;
-
-    std::vector<AddressInfo> addresses;
-    EXPECT_THROW(parseAddress(filter, hdr, "", addresses), std::runtime_error);
-    EXPECT_EQ(0, addresses.size());
-}
-
-TEST(ParseAddress, SmallMsg)
-{
-    nlmsghdr hdr{};
-    hdr.nlmsg_type = RTM_NEWADDR;
-    std::string data = "1";
-    AddressFilter filter;
-
-    std::vector<AddressInfo> addresses;
-    EXPECT_THROW(parseAddress(filter, hdr, data, addresses),
-                 std::runtime_error);
-    EXPECT_EQ(0, addresses.size());
-}
-
-TEST(ParseAddress, NoAttrs)
-{
-    nlmsghdr hdr{};
-    hdr.nlmsg_type = RTM_NEWADDR;
-    ifaddrmsg msg{};
-    msg.ifa_family = AF_INET;
-    msg.ifa_prefixlen = 24;
-    msg.ifa_index = 1;
-    msg.ifa_scope = RT_SCOPE_UNIVERSE;
-    std::string data;
-    data.append(reinterpret_cast<char*>(&msg), sizeof(msg));
-    AddressFilter filter;
-
-    std::vector<AddressInfo> addresses;
-    EXPECT_THROW(parseAddress(filter, hdr, data, addresses),
-                 std::runtime_error);
-    EXPECT_EQ(0, addresses.size());
-}
-
-TEST(ParseAddress, NoAddress)
-{
-    nlmsghdr hdr{};
-    hdr.nlmsg_type = RTM_NEWADDR;
-    ifaddrmsg msg{};
-    msg.ifa_family = AF_INET;
-    msg.ifa_prefixlen = 24;
-    msg.ifa_index = 1;
-    msg.ifa_scope = RT_SCOPE_UNIVERSE;
-    in_addr addr{};
-    rtattr local{};
-    constexpr auto len = RTA_LENGTH(sizeof(addr));
-    local.rta_len = len;
-    local.rta_type = IFA_LOCAL;
-    char localbuf[RTA_ALIGN(len)];
-    std::memset(localbuf, '\0', sizeof(localbuf));
-    std::memcpy(localbuf, &local, sizeof(local));
-    std::memcpy(RTA_DATA(localbuf), &addr, sizeof(addr));
-    std::string data;
-    data.append(reinterpret_cast<char*>(&msg), sizeof(msg));
-    data.append(reinterpret_cast<char*>(&localbuf), sizeof(localbuf));
-    AddressFilter filter;
-
-    std::vector<AddressInfo> addresses;
-    EXPECT_THROW(parseAddress(filter, hdr, data, addresses),
-                 std::runtime_error);
-    EXPECT_EQ(0, addresses.size());
-}
-
-TEST(ParseAddress, FilterInterface)
-{
-    nlmsghdr hdr{};
-    hdr.nlmsg_type = RTM_NEWADDR;
-    ifaddrmsg msg{};
-    msg.ifa_family = AF_INET;
-    msg.ifa_prefixlen = 24;
-    msg.ifa_index = 2;
-    msg.ifa_scope = RT_SCOPE_UNIVERSE;
-    in_addr addr;
-    ASSERT_EQ(1, inet_pton(msg.ifa_family, "192.168.10.1", &addr));
-    rtattr address{};
-    constexpr auto len = RTA_LENGTH(sizeof(addr));
-    address.rta_len = len;
-    address.rta_type = IFA_ADDRESS;
-    char addressbuf[RTA_ALIGN(len)];
-    std::memset(addressbuf, '\0', sizeof(addressbuf));
-    std::memcpy(addressbuf, &address, sizeof(address));
-    std::memcpy(RTA_DATA(addressbuf), &addr, sizeof(addr));
-    std::string data;
-    data.append(reinterpret_cast<char*>(&msg), sizeof(msg));
-    data.append(reinterpret_cast<char*>(&addressbuf), sizeof(addressbuf));
-    AddressFilter filter;
-
-    std::vector<AddressInfo> addresses;
-    filter.interface = 1;
-    parseAddress(filter, hdr, data, addresses);
-    EXPECT_EQ(0, addresses.size());
-    filter.interface = 2;
-    parseAddress(filter, hdr, data, addresses);
-    EXPECT_EQ(1, addresses.size());
-    EXPECT_EQ(msg.ifa_index, addresses[0].interface);
-    EXPECT_EQ(msg.ifa_scope, addresses[0].scope);
-    EXPECT_EQ(msg.ifa_prefixlen, addresses[0].prefix);
-    EXPECT_EQ(addr, addresses[0].address);
-}
-
-TEST(ParseNeighbor, FilterScope)
-{
-    nlmsghdr hdr{};
-    hdr.nlmsg_type = RTM_NEWADDR;
-    ifaddrmsg msg{};
-    msg.ifa_family = AF_INET;
-    msg.ifa_prefixlen = 24;
-    msg.ifa_index = 2;
-    msg.ifa_scope = RT_SCOPE_SITE;
-    in_addr addr;
-    ASSERT_EQ(1, inet_pton(msg.ifa_family, "192.168.10.1", &addr));
-    rtattr address{};
-    constexpr auto len = RTA_LENGTH(sizeof(addr));
-    address.rta_len = len;
-    address.rta_type = IFA_ADDRESS;
-    char addressbuf[RTA_ALIGN(len)];
-    std::memset(addressbuf, '\0', sizeof(addressbuf));
-    std::memcpy(addressbuf, &address, sizeof(address));
-    std::memcpy(RTA_DATA(addressbuf), &addr, sizeof(addr));
-    std::string data;
-    data.append(reinterpret_cast<char*>(&msg), sizeof(msg));
-    data.append(reinterpret_cast<char*>(&addressbuf), sizeof(addressbuf));
-    AddressFilter filter;
-
-    std::vector<AddressInfo> addresses;
-    filter.scope = RT_SCOPE_UNIVERSE;
-    parseAddress(filter, hdr, data, addresses);
-    EXPECT_EQ(0, addresses.size());
-    filter.scope = RT_SCOPE_SITE;
-    parseAddress(filter, hdr, data, addresses);
-    EXPECT_EQ(1, addresses.size());
-    EXPECT_EQ(msg.ifa_index, addresses[0].interface);
-    EXPECT_EQ(msg.ifa_scope, addresses[0].scope);
-    EXPECT_EQ(msg.ifa_prefixlen, addresses[0].prefix);
-    EXPECT_EQ(addr, addresses[0].address);
-}
-
-TEST(ParseNeighbor, NoFilter)
-{
-    nlmsghdr hdr{};
-    hdr.nlmsg_type = RTM_NEWADDR;
-    ifaddrmsg msg{};
-    msg.ifa_family = AF_INET6;
-    msg.ifa_prefixlen = 24;
-    msg.ifa_index = 1;
-    msg.ifa_scope = RT_SCOPE_UNIVERSE;
-    in6_addr addr;
-    ASSERT_EQ(1, inet_pton(msg.ifa_family, "fd00::2", &addr));
-    rtattr address{};
-    constexpr auto len = RTA_LENGTH(sizeof(addr));
-    address.rta_len = len;
-    address.rta_type = IFA_ADDRESS;
-    char addressbuf[RTA_ALIGN(len)];
-    std::memset(addressbuf, '\0', sizeof(addressbuf));
-    std::memcpy(addressbuf, &address, sizeof(address));
-    std::memcpy(RTA_DATA(addressbuf), &addr, sizeof(addr));
-    std::string data;
-    data.append(reinterpret_cast<char*>(&msg), sizeof(msg));
-    data.append(reinterpret_cast<char*>(&addressbuf), sizeof(addressbuf));
-    AddressFilter filter;
-
-    std::vector<AddressInfo> addresses;
-    parseAddress(filter, hdr, data, addresses);
-    EXPECT_EQ(1, addresses.size());
-    EXPECT_EQ(msg.ifa_index, addresses[0].interface);
-    EXPECT_EQ(msg.ifa_scope, addresses[0].scope);
-    EXPECT_EQ(msg.ifa_prefixlen, addresses[0].prefix);
-    EXPECT_EQ(addr, addresses[0].address);
-}
-
-} // namespace detail
-} // namespace network
-} // namespace phosphor
diff --git a/test/test_rtnetlink.cpp b/test/test_rtnetlink.cpp
index b11100f..9518cdc 100644
--- a/test/test_rtnetlink.cpp
+++ b/test/test_rtnetlink.cpp
@@ -1,90 +1,66 @@
-#include "mock_network_manager.hpp"
-#include "mock_syscall.hpp"
-#include "rtnetlink_server.hpp"
-#include "types.hpp"
+#include "rtnetlink.hpp"
 
+#include <linux/netlink.h>
 #include <linux/rtnetlink.h>
-#include <net/if.h>
 
-#include <chrono>
-#include <functional>
-#include <sdbusplus/bus.hpp>
-#include <sdeventplus/event.hpp>
-#include <testutil.hpp>
+#include <stdplus/raw.hpp>
 
 #include <gtest/gtest.h>
 
-namespace phosphor
+namespace phosphor::network::netlink
 {
 
-namespace network
+TEST(AddrFromRtm, MissingAddr)
 {
-sdbusplus::bus_t bus(sdbusplus::bus::new_default());
-extern std::unique_ptr<MockManager> manager;
-extern std::unique_ptr<Timer> refreshObjectTimer;
-EventPtr eventPtr = nullptr;
-
-class TestRtNetlink : public TestWithTmp
-{
-
-  public:
-    std::optional<rtnetlink::Server> svr;
-
-    TestRtNetlink()
+    struct
     {
-        manager = std::make_unique<MockManager>(bus, "/xyz/openbmc_test/bcd",
-                                                CaseTmpDir());
-        sd_event* events;
-        sd_event_default(&events);
-        eventPtr.reset(events);
-        events = nullptr;
-        initializeTimers();
-        createNetLinkSocket();
-        bus.attach_event(eventPtr.get(), SD_EVENT_PRIORITY_NORMAL);
-        svr.emplace(eventPtr);
-    }
-
-    void createNetLinkSocket()
-    {
-        // RtnetLink socket
-        auto fd = socket(PF_NETLINK, SOCK_RAW | SOCK_NONBLOCK, NETLINK_ROUTE);
-        smartSock.set(fd);
-    }
-};
-
-TEST_F(TestRtNetlink, WithSingleInterface)
-{
-    using namespace std::chrono;
-    mock_clear();
-    // Adds the following ip in the getifaddrs list.
-    mock_addIF("igb5", /*idx=*/6);
-    mock_addIP("igb5", "127.0.0.1", "255.255.255.128");
-    constexpr auto BUFSIZE = 4096;
-    std::array<char, BUFSIZE> msgBuf = {0};
-
-    // point the header and the msg structure pointers into the buffer.
-    auto nlMsg = reinterpret_cast<nlmsghdr*>(msgBuf.data());
-    // Length of message
-    nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(rtmsg));
-    nlMsg->nlmsg_type = RTM_GETADDR;
-    nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
-    nlMsg->nlmsg_seq = 0;
-    nlMsg->nlmsg_pid = getpid();
-
-    EXPECT_EQ(false, manager->hasInterface("igb5"));
-    // Send the request
-    send(svr->getSock(), nlMsg, nlMsg->nlmsg_len, 0);
-
-    int i = 3;
-    while (i--)
-    {
-        // wait for timer to expire
-        std::this_thread::sleep_for(std::chrono::milliseconds(refreshTimeout));
-        sd_event_run(eventPtr.get(), 10);
-    };
-
-    EXPECT_EQ(true, manager->hasInterface("igb5"));
+        alignas(NLMSG_ALIGNTO) ifaddrmsg ifa = {};
+    } msg;
+    EXPECT_THROW(addrFromRtm(stdplus::raw::asView<char>(msg)),
+                 std::runtime_error);
 }
 
-} // namespace network
-} // namespace phosphor
+TEST(AddrFromRtm, Regular)
+{
+    struct
+    {
+        alignas(NLMSG_ALIGNTO) ifaddrmsg ifa;
+        alignas(NLMSG_ALIGNTO) rtattr addr_hdr;
+        alignas(NLMSG_ALIGNTO) uint8_t addr[4] = {192, 168, 1, 20};
+    } msg;
+    msg.ifa.ifa_family = AF_INET;
+    msg.ifa.ifa_prefixlen = 28;
+    msg.ifa.ifa_flags = 4;
+    msg.ifa.ifa_scope = 3;
+    msg.ifa.ifa_index = 10;
+    msg.addr_hdr.rta_type = IFA_ADDRESS;
+    msg.addr_hdr.rta_len = RTA_LENGTH(sizeof(msg.addr));
+
+    auto ret = addrFromRtm(stdplus::raw::asView<char>(msg));
+    EXPECT_EQ(msg.ifa.ifa_flags, ret.flags);
+    EXPECT_EQ(msg.ifa.ifa_scope, ret.scope);
+    EXPECT_EQ(msg.ifa.ifa_index, ret.ifidx);
+    EXPECT_EQ((IfAddr{in_addr{hton(0xc0a80114)}, 28}), ret.ifaddr);
+}
+
+TEST(AddrFromRtm, ExtraFlags)
+{
+    struct
+    {
+        alignas(NLMSG_ALIGNTO) ifaddrmsg ifa = {};
+        alignas(NLMSG_ALIGNTO) rtattr flags_hdr;
+        alignas(NLMSG_ALIGNTO) uint32_t flags = 0xff00ff00;
+        alignas(NLMSG_ALIGNTO) rtattr addr_hdr;
+        alignas(NLMSG_ALIGNTO) uint8_t addr[16] = {};
+    } msg;
+    msg.ifa.ifa_family = AF_INET6;
+    msg.flags_hdr.rta_type = IFA_FLAGS;
+    msg.flags_hdr.rta_len = RTA_LENGTH(sizeof(msg.flags));
+    msg.addr_hdr.rta_type = IFA_ADDRESS;
+    msg.addr_hdr.rta_len = RTA_LENGTH(sizeof(msg.addr));
+
+    auto ret = addrFromRtm(stdplus::raw::asView<char>(msg));
+    EXPECT_EQ(0xff00ff00, ret.flags);
+}
+
+} // namespace phosphor::network::netlink
diff --git a/test/test_rtnetlink_server.cpp b/test/test_rtnetlink_server.cpp
new file mode 100644
index 0000000..b11100f
--- /dev/null
+++ b/test/test_rtnetlink_server.cpp
@@ -0,0 +1,90 @@
+#include "mock_network_manager.hpp"
+#include "mock_syscall.hpp"
+#include "rtnetlink_server.hpp"
+#include "types.hpp"
+
+#include <linux/rtnetlink.h>
+#include <net/if.h>
+
+#include <chrono>
+#include <functional>
+#include <sdbusplus/bus.hpp>
+#include <sdeventplus/event.hpp>
+#include <testutil.hpp>
+
+#include <gtest/gtest.h>
+
+namespace phosphor
+{
+
+namespace network
+{
+sdbusplus::bus_t bus(sdbusplus::bus::new_default());
+extern std::unique_ptr<MockManager> manager;
+extern std::unique_ptr<Timer> refreshObjectTimer;
+EventPtr eventPtr = nullptr;
+
+class TestRtNetlink : public TestWithTmp
+{
+
+  public:
+    std::optional<rtnetlink::Server> svr;
+
+    TestRtNetlink()
+    {
+        manager = std::make_unique<MockManager>(bus, "/xyz/openbmc_test/bcd",
+                                                CaseTmpDir());
+        sd_event* events;
+        sd_event_default(&events);
+        eventPtr.reset(events);
+        events = nullptr;
+        initializeTimers();
+        createNetLinkSocket();
+        bus.attach_event(eventPtr.get(), SD_EVENT_PRIORITY_NORMAL);
+        svr.emplace(eventPtr);
+    }
+
+    void createNetLinkSocket()
+    {
+        // RtnetLink socket
+        auto fd = socket(PF_NETLINK, SOCK_RAW | SOCK_NONBLOCK, NETLINK_ROUTE);
+        smartSock.set(fd);
+    }
+};
+
+TEST_F(TestRtNetlink, WithSingleInterface)
+{
+    using namespace std::chrono;
+    mock_clear();
+    // Adds the following ip in the getifaddrs list.
+    mock_addIF("igb5", /*idx=*/6);
+    mock_addIP("igb5", "127.0.0.1", "255.255.255.128");
+    constexpr auto BUFSIZE = 4096;
+    std::array<char, BUFSIZE> msgBuf = {0};
+
+    // point the header and the msg structure pointers into the buffer.
+    auto nlMsg = reinterpret_cast<nlmsghdr*>(msgBuf.data());
+    // Length of message
+    nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(rtmsg));
+    nlMsg->nlmsg_type = RTM_GETADDR;
+    nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
+    nlMsg->nlmsg_seq = 0;
+    nlMsg->nlmsg_pid = getpid();
+
+    EXPECT_EQ(false, manager->hasInterface("igb5"));
+    // Send the request
+    send(svr->getSock(), nlMsg, nlMsg->nlmsg_len, 0);
+
+    int i = 3;
+    while (i--)
+    {
+        // wait for timer to expire
+        std::this_thread::sleep_for(std::chrono::milliseconds(refreshTimeout));
+        sd_event_run(eventPtr.get(), 10);
+    };
+
+    EXPECT_EQ(true, manager->hasInterface("igb5"));
+}
+
+} // namespace network
+} // namespace phosphor
diff --git a/test/test_system_queries.cpp b/test/test_system_queries.cpp
index d615a87..047d968 100644
--- a/test/test_system_queries.cpp
+++ b/test/test_system_queries.cpp
@@ -111,5 +111,16 @@
     EXPECT_TRUE(validateNewInterface(info));
 }
 
+TEST(ValidateNewAddr, Filtering)
+{
+    AddressInfo info = {};
+    EXPECT_TRUE(validateNewAddr(info, {}));
+
+    info.ifidx = 2;
+    EXPECT_TRUE(validateNewAddr(info, {}));
+    EXPECT_TRUE(validateNewAddr(info, {.ifidx = 2}));
+    EXPECT_FALSE(validateNewAddr(info, {.ifidx = 3}));
+}
+
 } // namespace detail
 } // namespace phosphor::network::system