#include "rtnetlink_server.hpp" #include #include #include #include #include #include #include #include #include #include #include namespace phosphor { namespace network { extern std::unique_ptr refreshObjectTimer; namespace rtnetlink { static bool shouldRefresh(const struct nlmsghdr& hdr, std::string_view data) { switch (hdr.nlmsg_type) { case RTM_NEWADDR: case RTM_DELADDR: case RTM_NEWROUTE: case RTM_DELROUTE: { 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; } /* Call Back for the sd event loop */ static int eventHandler(sd_event_source* /*es*/, int fd, uint32_t /*revents*/, void* /*userdata*/) { std::array buffer = {}; int len{}; auto netLinkHeader = reinterpret_cast(buffer.data()); while ((len = recv(fd, netLinkHeader, phosphor::network::rtnetlink::BUFSIZE, 0)) > 0) { for (; (NLMSG_OK(netLinkHeader, len)) && (netLinkHeader->nlmsg_type != NLMSG_DONE); netLinkHeader = NLMSG_NEXT(netLinkHeader, len)) { std::string_view data( reinterpret_cast(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. if (!refreshObjectTimer->isEnabled()) { // if start timer throws exception then let the application // crash refreshObjectTimer->restartOnce(refreshTimeout); } // end if } // end if } // end for buffer.fill('\0'); netLinkHeader = reinterpret_cast(buffer.data()); } // end while return 0; } static stdplus::ManagedFd makeSock() { using namespace stdplus::fd; auto sock = socket(SocketDomain::Netlink, SocketType::Raw, static_cast(NETLINK_ROUTE)); sock.fcntlSetfl(sock.fcntlGetfl().set(FileFlag::NonBlock)); sockaddr_nl local{}; local.nl_family = AF_NETLINK; local.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NEIGH; bind(sock, local); return sock; } Server::Server(EventPtr& eventPtr) : sock(makeSock()) { using namespace phosphor::logging; using InternalFailure = sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; int r{}; /* Let's make use of the default handler and "floating" reference features of sd_event_add_signal() */ stdplus::signal::block(SIGTERM); r = sd_event_add_signal(eventPtr.get(), NULL, SIGTERM, NULL, NULL); if (r < 0) { goto finish; } stdplus::signal::block(SIGINT); r = sd_event_add_signal(eventPtr.get(), NULL, SIGINT, NULL, NULL); if (r < 0) { goto finish; } r = sd_event_add_io(eventPtr.get(), nullptr, sock.get(), EPOLLIN, eventHandler, nullptr); if (r < 0) { goto finish; } finish: if (r < 0) { log("Failure Occurred in starting of server:", entry("ERRNO=%d", errno)); elog(); } } } // namespace rtnetlink } // namespace network } // namespace phosphor