rtnetlink: Migrate IP functions
Change-Id: I4c87b59306911df4c5a73e441b2b962fbaab072c
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/ethernet_interface.cpp b/src/ethernet_interface.cpp
index c2e3e63..a0c6193 100644
--- a/src/ethernet_interface.cpp
+++ b/src/ethernet_interface.cpp
@@ -176,19 +176,14 @@
void EthernetInterface::createIPAddressObjects()
{
addrs.clear();
-
- AddressFilter filter;
- filter.interface = ifIdx;
- auto currentAddrs = getCurrentAddresses(filter);
- for (const auto& addr : currentAddrs)
+ for (const auto& addr : system::getAddresses({.ifidx = ifIdx}))
{
if (addr.flags & IFA_F_DEPRECATED)
{
continue;
}
- auto ifaddr = IfAddr(addr.address, addr.prefix);
IP::AddressOrigin origin = IP::AddressOrigin::Static;
- if (dhcpIsEnabled(addr.address))
+ if (dhcpIsEnabled(addr.ifaddr.getAddr()))
{
origin = IP::AddressOrigin::DHCP;
}
@@ -200,8 +195,9 @@
#endif
this->addrs.insert_or_assign(
- ifaddr, std::make_unique<IPAddress>(bus, std::string_view(objPath),
- *this, ifaddr, origin));
+ addr.ifaddr,
+ std::make_unique<IPAddress>(bus, std::string_view(objPath), *this,
+ addr.ifaddr, origin));
}
}
diff --git a/src/ipaddress.cpp b/src/ipaddress.cpp
index 647c37e..560129d 100644
--- a/src/ipaddress.cpp
+++ b/src/ipaddress.cpp
@@ -1,20 +1,14 @@
#include "ipaddress.hpp"
#include "ethernet_interface.hpp"
-#include "netlink.hpp"
#include "network_manager.hpp"
#include "util.hpp"
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/log.hpp>
#include <stdexcept>
-#include <stdplus/raw.hpp>
#include <string>
#include <string_view>
-#include <vector>
#include <xyz/openbmc_project/Common/error.hpp>
namespace phosphor
@@ -22,18 +16,6 @@
namespace network
{
-std::vector<AddressInfo> getCurrentAddresses(const AddressFilter& filter)
-{
- std::vector<AddressInfo> addresses;
- auto cb = [&filter, &addresses](const nlmsghdr& hdr, std::string_view msg) {
- detail::parseAddress(filter, hdr, msg, addresses);
- };
- ifaddrmsg msg{};
- msg.ifa_index = filter.interface;
- netlink::performRequest(NETLINK_ROUTE, RTM_GETADDR, NLM_F_DUMP, msg, cb);
- return addresses;
-}
-
using namespace phosphor::logging;
using namespace sdbusplus::xyz::openbmc_project::Common::Error;
using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
@@ -132,56 +114,5 @@
parent.manager.reloadConfigs();
}
-namespace detail
-{
-
-void parseAddress(const AddressFilter& filter, const nlmsghdr& hdr,
- std::string_view msg, std::vector<AddressInfo>& addresses)
-{
- if (hdr.nlmsg_type != RTM_NEWADDR)
- {
- throw std::runtime_error("Not an address msg");
- }
- const auto& ifaddr = netlink::extractRtData<ifaddrmsg>(msg);
-
- // Filter out addresses we don't care about
- unsigned ifindex = ifaddr.ifa_index;
- if (filter.interface != 0 && filter.interface != ifindex)
- {
- return;
- }
- if (filter.scope && *filter.scope != ifaddr.ifa_scope)
- {
- return;
- }
-
- // Build the info about the address we found
- AddressInfo address;
- address.interface = ifindex;
- address.prefix = ifaddr.ifa_prefixlen;
- address.flags = ifaddr.ifa_flags;
- address.scope = ifaddr.ifa_scope;
- bool set_addr = false;
- while (!msg.empty())
- {
- auto [hdr, data] = netlink::extractRtAttr(msg);
- if (hdr.rta_type == IFA_ADDRESS)
- {
- address.address = addrFromBuf(ifaddr.ifa_family, data);
- set_addr = true;
- }
- else if (hdr.rta_type == IFA_FLAGS)
- {
- address.flags = stdplus::raw::extract<uint32_t>(data);
- }
- }
- if (!set_addr)
- {
- throw std::runtime_error("Missing address");
- }
- addresses.push_back(std::move(address));
-}
-
-} // namespace detail
} // namespace network
} // namespace phosphor
diff --git a/src/ipaddress.hpp b/src/ipaddress.hpp
index 94bdfdb..05aafbd 100644
--- a/src/ipaddress.hpp
+++ b/src/ipaddress.hpp
@@ -1,16 +1,10 @@
#pragma once
#include "types.hpp"
-#include <linux/netlink.h>
-
-#include <cstdint>
-#include <optional>
#include <sdbusplus/bus.hpp>
#include <sdbusplus/message/native_types.hpp>
#include <sdbusplus/server/object.hpp>
-#include <string>
#include <string_view>
-#include <vector>
#include <xyz/openbmc_project/Network/IP/server.hpp>
#include <xyz/openbmc_project/Object/Delete/server.hpp>
@@ -27,30 +21,6 @@
class EthernetInterface;
-/* @class AddressFilter
- */
-struct AddressFilter
-{
- unsigned interface = 0;
- std::optional<uint8_t> scope;
-};
-
-/** @class AddressInfo
- * @brief Information about a addresses from the kernel
- */
-struct AddressInfo
-{
- unsigned interface;
- InAddrAny address;
- uint8_t prefix;
- uint8_t scope;
- uint32_t flags;
-};
-
-/** @brief Returns a list of the current system neighbor table
- */
-std::vector<AddressInfo> getCurrentAddresses(const AddressFilter& filter);
-
/** @class IPAddress
* @brief OpenBMC IPAddress implementation.
* @details A concrete implementation for the
@@ -109,12 +79,5 @@
EthernetInterface& parent, IfAddr addr, IP::AddressOrigin origin);
};
-namespace detail
-{
-
-void parseAddress(const AddressFilter& filter, const nlmsghdr& hdr,
- std::string_view msg, std::vector<AddressInfo>& addresses);
-
-} // namespace detail
} // namespace network
} // namespace phosphor
diff --git a/src/rtnetlink.cpp b/src/rtnetlink.cpp
index 6e0946f..5d6e660 100644
--- a/src/rtnetlink.cpp
+++ b/src/rtnetlink.cpp
@@ -1,6 +1,7 @@
#include "rtnetlink.hpp"
#include "netlink.hpp"
+#include "util.hpp"
#include <linux/rtnetlink.h>
@@ -19,10 +20,10 @@
switch (hdr.rta_type)
{
case RTA_OIF:
- ifIdx.emplace(stdplus::raw::copyFrom<int>(data));
+ ifIdx.emplace(stdplus::raw::copyFromStrict<int>(data));
break;
case RTA_GATEWAY:
- gw.emplace(stdplus::raw::copyFrom<Addr>(data));
+ gw.emplace(stdplus::raw::copyFromStrict<Addr>(data));
break;
}
}
@@ -51,4 +52,33 @@
return std::nullopt;
}
+AddressInfo addrFromRtm(std::string_view msg)
+{
+ const auto& ifa = extractRtData<ifaddrmsg>(msg);
+
+ AddressInfo ret;
+ ret.ifidx = ifa.ifa_index;
+ ret.flags = ifa.ifa_flags;
+ ret.scope = ifa.ifa_scope;
+ std::optional<InAddrAny> addr;
+ while (!msg.empty())
+ {
+ auto [hdr, data] = extractRtAttr(msg);
+ if (hdr.rta_type == IFA_ADDRESS)
+ {
+ addr.emplace(addrFromBuf(ifa.ifa_family, data));
+ }
+ else if (hdr.rta_type == IFA_FLAGS)
+ {
+ ret.flags = stdplus::raw::copyFromStrict<uint32_t>(data);
+ }
+ }
+ if (!addr)
+ {
+ throw std::runtime_error("Missing address");
+ }
+ ret.ifaddr = {*addr, ifa.ifa_prefixlen};
+ return ret;
+}
+
} // namespace phosphor::network::netlink
diff --git a/src/rtnetlink.hpp b/src/rtnetlink.hpp
index 41df902..48f3820 100644
--- a/src/rtnetlink.hpp
+++ b/src/rtnetlink.hpp
@@ -7,6 +7,10 @@
namespace phosphor::network::netlink
{
+
std::optional<std::tuple<unsigned, InAddrAny>>
gatewayFromRtm(std::string_view msg);
-}
+
+AddressInfo addrFromRtm(std::string_view msg);
+
+} // namespace phosphor::network::netlink
diff --git a/src/system_queries.cpp b/src/system_queries.cpp
index f0222ec..5aba1d2 100644
--- a/src/system_queries.cpp
+++ b/src/system_queries.cpp
@@ -1,6 +1,7 @@
#include "system_queries.hpp"
#include "netlink.hpp"
+#include "rtnetlink.hpp"
#include "util.hpp"
#include <fmt/format.h>
@@ -224,6 +225,16 @@
return true;
}
+bool detail::validateNewAddr(const AddressInfo& info,
+ const AddressFilter& filter) noexcept
+{
+ if (filter.ifidx != 0 && filter.ifidx != info.ifidx)
+ {
+ return false;
+ }
+ return true;
+}
+
std::vector<InterfaceInfo> getInterfaces()
{
std::vector<InterfaceInfo> ret;
@@ -239,4 +250,20 @@
return ret;
}
+std::vector<AddressInfo> getAddresses(const AddressFilter& filter)
+{
+ std::vector<AddressInfo> ret;
+ auto cb = [&](const nlmsghdr&, std::string_view msg) {
+ auto info = netlink::addrFromRtm(msg);
+ if (detail::validateNewAddr(info, filter))
+ {
+ ret.emplace_back(std::move(info));
+ }
+ };
+ ifaddrmsg msg{};
+ msg.ifa_index = filter.ifidx;
+ netlink::performRequest(NETLINK_ROUTE, RTM_GETADDR, NLM_F_DUMP, msg, cb);
+ return ret;
+}
+
} // namespace phosphor::network::system
diff --git a/src/system_queries.hpp b/src/system_queries.hpp
index 32d54cf..97a5faa 100644
--- a/src/system_queries.hpp
+++ b/src/system_queries.hpp
@@ -53,10 +53,17 @@
}
};
+struct AddressFilter
+{
+ unsigned ifidx = 0;
+};
+
namespace detail
{
InterfaceInfo parseInterface(const nlmsghdr& hdr, std::string_view msg);
bool validateNewInterface(const InterfaceInfo& info);
+bool validateNewAddr(const AddressInfo& info,
+ const AddressFilter& filter) noexcept;
} // namespace detail
/** @brief Get all the interfaces from the system.
@@ -64,4 +71,9 @@
*/
std::vector<InterfaceInfo> getInterfaces();
+/** @brief Get all the addreses from the system.
+ * @returns list of addresses
+ */
+std::vector<AddressInfo> getAddresses(const AddressFilter& filter);
+
} // namespace phosphor::network::system
diff --git a/src/types.hpp b/src/types.hpp
index 4515211..8755068 100644
--- a/src/types.hpp
+++ b/src/types.hpp
@@ -75,6 +75,17 @@
using Timer = sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>;
+/** @class AddressInfo
+ * @brief Information about a addresses from the kernel
+ */
+struct AddressInfo
+{
+ unsigned ifidx;
+ IfAddr ifaddr;
+ uint8_t scope;
+ uint32_t flags;
+};
+
struct string_hash : public std::hash<std::string_view>
{
using is_transparent = void;
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