1 #include "rtnetlink_server.hpp" 2 3 #include "types.hpp" 4 5 #include <linux/netlink.h> 6 #include <linux/rtnetlink.h> 7 #include <netinet/in.h> 8 9 #include <memory> 10 #include <stdplus/fd/create.hpp> 11 #include <stdplus/fd/ops.hpp> 12 #include <string_view> 13 14 namespace phosphor 15 { 16 namespace network 17 { 18 19 extern std::unique_ptr<Timer> refreshObjectTimer; 20 21 namespace rtnetlink 22 { 23 24 static bool shouldRefresh(const struct nlmsghdr& hdr, std::string_view data) 25 { 26 switch (hdr.nlmsg_type) 27 { 28 case RTM_NEWADDR: 29 case RTM_DELADDR: 30 case RTM_NEWROUTE: 31 case RTM_DELROUTE: 32 { 33 return true; 34 } 35 case RTM_NEWNEIGH: 36 case RTM_DELNEIGH: 37 { 38 struct ndmsg ndm; 39 if (data.size() < sizeof(ndm)) 40 { 41 return false; 42 } 43 memcpy(&ndm, data.data(), sizeof(ndm)); 44 // We only want to refresh for static neighbors 45 return ndm.ndm_state & NUD_PERMANENT; 46 } 47 } 48 49 return false; 50 } 51 52 /* Call Back for the sd event loop */ 53 static void eventHandler(sdeventplus::source::IO&, int fd, uint32_t) 54 { 55 std::array<char, BUFSIZE> buffer = {}; 56 int len{}; 57 58 auto netLinkHeader = reinterpret_cast<struct nlmsghdr*>(buffer.data()); 59 60 while ((len = recv(fd, netLinkHeader, buffer.size(), 0)) > 0) 61 { 62 for (; (NLMSG_OK(netLinkHeader, len)) && 63 (netLinkHeader->nlmsg_type != NLMSG_DONE); 64 netLinkHeader = NLMSG_NEXT(netLinkHeader, len)) 65 { 66 std::string_view data( 67 reinterpret_cast<const char*>(NLMSG_DATA(netLinkHeader)), 68 netLinkHeader->nlmsg_len - NLMSG_HDRLEN); 69 if (shouldRefresh(*netLinkHeader, data)) 70 { 71 // starting the timer here to make sure that we don't want 72 // create the child objects multiple times. 73 if (!refreshObjectTimer->isEnabled()) 74 { 75 // if start timer throws exception then let the application 76 // crash 77 refreshObjectTimer->restartOnce(refreshTimeout); 78 } // end if 79 } // end if 80 81 } // end for 82 83 buffer.fill('\0'); 84 85 netLinkHeader = reinterpret_cast<struct nlmsghdr*>(buffer.data()); 86 } // end while 87 } 88 89 static stdplus::ManagedFd makeSock() 90 { 91 using namespace stdplus::fd; 92 93 auto sock = socket(SocketDomain::Netlink, SocketType::Raw, 94 static_cast<stdplus::fd::SocketProto>(NETLINK_ROUTE)); 95 96 sock.fcntlSetfl(sock.fcntlGetfl().set(FileFlag::NonBlock)); 97 98 sockaddr_nl local{}; 99 local.nl_family = AF_NETLINK; 100 local.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | 101 RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NEIGH; 102 bind(sock, local); 103 104 return sock; 105 } 106 107 Server::Server(sdeventplus::Event& event) : 108 sock(makeSock()), io(event, sock.get(), EPOLLIN | EPOLLET, eventHandler) 109 { 110 } 111 112 } // namespace rtnetlink 113 } // namespace network 114 } // namespace phosphor 115