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 char buffer[phosphor::network::rtnetlink::BUFSIZE]{}; 63 int len{}; 64 65 auto netLinkHeader = reinterpret_cast<struct nlmsghdr*>(buffer); 66 while ((len = recv(fd, netLinkHeader, phosphor::network::rtnetlink::BUFSIZE, 67 0)) > 0) 68 { 69 for (; (NLMSG_OK(netLinkHeader, len)) && 70 (netLinkHeader->nlmsg_type != NLMSG_DONE); 71 netLinkHeader = NLMSG_NEXT(netLinkHeader, len)) 72 { 73 std::string_view data( 74 reinterpret_cast<const char*>(NLMSG_DATA(netLinkHeader)), 75 netLinkHeader->nlmsg_len - NLMSG_HDRLEN); 76 if (shouldRefresh(*netLinkHeader, data)) 77 { 78 // starting the timer here to make sure that we don't want 79 // create the child objects multiple times. 80 if (!refreshObjectTimer->isEnabled()) 81 { 82 // if start timer throws exception then let the application 83 // crash 84 refreshObjectTimer->restartOnce(refreshTimeout); 85 } // end if 86 } // end if 87 88 } // end for 89 90 } // end while 91 92 return 0; 93 } 94 95 Server::Server(EventPtr& eventPtr, const phosphor::Descriptor& smartSock) 96 { 97 using namespace phosphor::logging; 98 using InternalFailure = 99 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 100 struct sockaddr_nl addr 101 { 102 }; 103 int r{}; 104 105 sigset_t ss{}; 106 // check that the given socket is valid or not. 107 if (smartSock() < 0) 108 { 109 r = -EBADF; 110 goto finish; 111 } 112 113 if (sigemptyset(&ss) < 0 || sigaddset(&ss, SIGTERM) < 0 || 114 sigaddset(&ss, SIGINT) < 0) 115 { 116 r = -errno; 117 goto finish; 118 } 119 /* Block SIGTERM first, so that the event loop can handle it */ 120 if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0) 121 { 122 r = -errno; 123 goto finish; 124 } 125 126 /* Let's make use of the default handler and "floating" 127 reference features of sd_event_add_signal() */ 128 129 r = sd_event_add_signal(eventPtr.get(), NULL, SIGTERM, NULL, NULL); 130 if (r < 0) 131 { 132 goto finish; 133 } 134 135 r = sd_event_add_signal(eventPtr.get(), NULL, SIGINT, NULL, NULL); 136 if (r < 0) 137 { 138 goto finish; 139 } 140 141 std::memset(&addr, 0, sizeof(addr)); 142 addr.nl_family = AF_NETLINK; 143 addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | 144 RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NEIGH; 145 146 if (bind(smartSock(), (struct sockaddr*)&addr, sizeof(addr)) < 0) 147 { 148 r = -errno; 149 goto finish; 150 } 151 152 r = sd_event_add_io(eventPtr.get(), nullptr, smartSock(), EPOLLIN, 153 eventHandler, nullptr); 154 if (r < 0) 155 { 156 goto finish; 157 } 158 159 finish: 160 161 if (r < 0) 162 { 163 log<level::ERR>("Failure Occurred in starting of server:", 164 entry("ERRNO=%d", errno)); 165 elog<InternalFailure>(); 166 } 167 } 168 169 } // namespace rtnetlink 170 } // namespace network 171 } // namespace phosphor 172