1 #include "rtnetlink_server.hpp" 2 3 #include "netlink.hpp" 4 #include "types.hpp" 5 6 #include <linux/netlink.h> 7 #include <linux/rtnetlink.h> 8 #include <netinet/in.h> 9 10 #include <memory> 11 #include <stdplus/fd/create.hpp> 12 #include <stdplus/fd/ops.hpp> 13 #include <string_view> 14 15 namespace phosphor 16 { 17 namespace network 18 { 19 20 extern std::unique_ptr<Timer> refreshObjectTimer; 21 22 namespace netlink 23 { 24 25 static bool shouldRefresh(const struct nlmsghdr& hdr, 26 std::string_view data) noexcept 27 { 28 switch (hdr.nlmsg_type) 29 { 30 case RTM_NEWADDR: 31 case RTM_DELADDR: 32 case RTM_NEWROUTE: 33 case RTM_DELROUTE: 34 { 35 return true; 36 } 37 case RTM_NEWNEIGH: 38 case RTM_DELNEIGH: 39 { 40 struct ndmsg ndm; 41 if (data.size() < sizeof(ndm)) 42 { 43 return false; 44 } 45 memcpy(&ndm, data.data(), sizeof(ndm)); 46 // We only want to refresh for static neighbors 47 return ndm.ndm_state & NUD_PERMANENT; 48 } 49 } 50 51 return false; 52 } 53 54 static void handler(const nlmsghdr& hdr, std::string_view data) 55 { 56 if (shouldRefresh(hdr, data) && !refreshObjectTimer->isEnabled()) 57 { 58 refreshObjectTimer->restartOnce(refreshTimeout); 59 } 60 } 61 62 static void eventHandler(sdeventplus::source::IO&, int fd, uint32_t) 63 { 64 receive(fd, handler); 65 } 66 67 static stdplus::ManagedFd makeSock() 68 { 69 using namespace stdplus::fd; 70 71 auto sock = socket(SocketDomain::Netlink, SocketType::Raw, 72 static_cast<stdplus::fd::SocketProto>(NETLINK_ROUTE)); 73 74 sock.fcntlSetfl(sock.fcntlGetfl().set(FileFlag::NonBlock)); 75 76 sockaddr_nl local{}; 77 local.nl_family = AF_NETLINK; 78 local.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | 79 RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NEIGH; 80 bind(sock, local); 81 82 return sock; 83 } 84 85 Server::Server(sdeventplus::Event& event) : 86 sock(makeSock()), io(event, sock.get(), EPOLLIN | EPOLLET, eventHandler) 87 { 88 } 89 90 } // namespace netlink 91 } // namespace network 92 } // namespace phosphor 93