1 #include "rtnetlink_server.hpp" 2 3 #include "types.hpp" 4 #include "util.hpp" 5 6 #include <linux/netlink.h> 7 #include <linux/rtnetlink.h> 8 #include <net/if.h> 9 #include <netinet/in.h> 10 #include <sys/types.h> 11 #include <systemd/sd-daemon.h> 12 #include <unistd.h> 13 14 #include <memory> 15 #include <phosphor-logging/elog-errors.hpp> 16 #include <phosphor-logging/log.hpp> 17 #include <string_view> 18 #include <xyz/openbmc_project/Common/error.hpp> 19 20 namespace phosphor 21 { 22 namespace network 23 { 24 25 extern std::unique_ptr<Timer> refreshObjectTimer; 26 27 namespace rtnetlink 28 { 29 30 static bool shouldRefresh(const struct nlmsghdr& hdr, std::string_view data) 31 { 32 switch (hdr.nlmsg_type) 33 { 34 case RTM_NEWADDR: 35 case RTM_DELADDR: 36 case RTM_NEWROUTE: 37 case RTM_DELROUTE: 38 { 39 return true; 40 } 41 case RTM_NEWNEIGH: 42 case RTM_DELNEIGH: 43 { 44 struct ndmsg ndm; 45 if (data.size() < sizeof(ndm)) 46 { 47 return false; 48 } 49 memcpy(&ndm, data.data(), sizeof(ndm)); 50 // We only want to refresh for static neighbors 51 return ndm.ndm_state & NUD_PERMANENT; 52 } 53 } 54 55 return false; 56 } 57 58 /* Call Back for the sd event loop */ 59 static int eventHandler(sd_event_source* /*es*/, int fd, uint32_t /*revents*/, 60 void* /*userdata*/) 61 { 62 std::array<char, phosphor::network::rtnetlink::BUFSIZE> buffer = {}; 63 int len{}; 64 65 auto netLinkHeader = reinterpret_cast<struct nlmsghdr*>(buffer.data()); 66 67 while ((len = recv(fd, netLinkHeader, phosphor::network::rtnetlink::BUFSIZE, 68 0)) > 0) 69 { 70 for (; (NLMSG_OK(netLinkHeader, len)) && 71 (netLinkHeader->nlmsg_type != NLMSG_DONE); 72 netLinkHeader = NLMSG_NEXT(netLinkHeader, len)) 73 { 74 std::string_view data( 75 reinterpret_cast<const char*>(NLMSG_DATA(netLinkHeader)), 76 netLinkHeader->nlmsg_len - NLMSG_HDRLEN); 77 if (shouldRefresh(*netLinkHeader, data)) 78 { 79 // starting the timer here to make sure that we don't want 80 // create the child objects multiple times. 81 if (!refreshObjectTimer->isEnabled()) 82 { 83 // if start timer throws exception then let the application 84 // crash 85 refreshObjectTimer->restartOnce(refreshTimeout); 86 } // end if 87 } // end if 88 89 } // end for 90 91 buffer.fill('\0'); 92 93 netLinkHeader = reinterpret_cast<struct nlmsghdr*>(buffer.data()); 94 } // end while 95 96 return 0; 97 } 98 99 Server::Server(EventPtr& eventPtr, const phosphor::Descriptor& smartSock) 100 { 101 using namespace phosphor::logging; 102 using InternalFailure = 103 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 104 struct sockaddr_nl addr 105 { 106 }; 107 int r{}; 108 109 sigset_t ss{}; 110 // check that the given socket is valid or not. 111 if (smartSock() < 0) 112 { 113 r = -EBADF; 114 goto finish; 115 } 116 117 if (sigemptyset(&ss) < 0 || sigaddset(&ss, SIGTERM) < 0 || 118 sigaddset(&ss, SIGINT) < 0) 119 { 120 r = -errno; 121 goto finish; 122 } 123 /* Block SIGTERM first, so that the event loop can handle it */ 124 if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0) 125 { 126 r = -errno; 127 goto finish; 128 } 129 130 /* Let's make use of the default handler and "floating" 131 reference features of sd_event_add_signal() */ 132 133 r = sd_event_add_signal(eventPtr.get(), NULL, SIGTERM, NULL, NULL); 134 if (r < 0) 135 { 136 goto finish; 137 } 138 139 r = sd_event_add_signal(eventPtr.get(), NULL, SIGINT, NULL, NULL); 140 if (r < 0) 141 { 142 goto finish; 143 } 144 145 std::memset(&addr, 0, sizeof(addr)); 146 addr.nl_family = AF_NETLINK; 147 addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | 148 RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NEIGH; 149 150 if (bind(smartSock(), (struct sockaddr*)&addr, sizeof(addr)) < 0) 151 { 152 r = -errno; 153 goto finish; 154 } 155 156 r = sd_event_add_io(eventPtr.get(), nullptr, smartSock(), EPOLLIN, 157 eventHandler, nullptr); 158 if (r < 0) 159 { 160 goto finish; 161 } 162 163 finish: 164 165 if (r < 0) 166 { 167 log<level::ERR>("Failure Occurred in starting of server:", 168 entry("ERRNO=%d", errno)); 169 elog<InternalFailure>(); 170 } 171 } 172 173 } // namespace rtnetlink 174 } // namespace network 175 } // namespace phosphor 176