1 #include "rtnetlink_server.hpp" 2 3 #include "netlink.hpp" 4 #include "network_manager.hpp" 5 #include "rtnetlink.hpp" 6 #include "types.hpp" 7 8 #include <linux/netlink.h> 9 #include <linux/rtnetlink.h> 10 #include <netinet/in.h> 11 12 #include <memory> 13 #include <phosphor-logging/log.hpp> 14 #include <stdplus/fd/create.hpp> 15 #include <stdplus/fd/ops.hpp> 16 #include <string_view> 17 18 namespace phosphor 19 { 20 namespace network 21 { 22 23 extern std::unique_ptr<Timer> refreshObjectTimer; 24 25 namespace netlink 26 { 27 28 using phosphor::logging::entry; 29 using phosphor::logging::level; 30 using phosphor::logging::log; 31 32 static bool shouldRefresh(const struct nlmsghdr& hdr, 33 std::string_view data) noexcept 34 { 35 switch (hdr.nlmsg_type) 36 { 37 case RTM_NEWLINK: 38 case RTM_DELLINK: 39 return true; 40 case RTM_NEWNEIGH: 41 case RTM_DELNEIGH: 42 { 43 if (data.size() < sizeof(ndmsg)) 44 { 45 return false; 46 } 47 const auto& ndm = *reinterpret_cast<const ndmsg*>(data.data()); 48 // We only want to refresh for static neighbors 49 return ndm.ndm_state & NUD_PERMANENT; 50 } 51 } 52 return false; 53 } 54 55 static void rthandler(Manager& m, bool n, std::string_view data) 56 { 57 auto ret = netlink::gatewayFromRtm(data); 58 if (!ret) 59 { 60 return; 61 } 62 auto ifIdx = std::get<unsigned>(*ret); 63 auto it = m.interfacesByIdx.find(ifIdx); 64 if (it == m.interfacesByIdx.end()) 65 { 66 auto msg = fmt::format("Interface `{}` not found for route", ifIdx); 67 log<level::ERR>(msg.c_str(), entry("IFIDX=%u", ifIdx)); 68 return; 69 } 70 std::visit( 71 [&](auto addr) { 72 if constexpr (std::is_same_v<in_addr, decltype(addr)>) 73 { 74 if (n) 75 { 76 it->second->EthernetInterfaceIntf::defaultGateway( 77 std::to_string(addr)); 78 } 79 else if (it->second->defaultGateway() == std::to_string(addr)) 80 { 81 it->second->EthernetInterfaceIntf::defaultGateway(""); 82 } 83 } 84 else if constexpr (std::is_same_v<in6_addr, decltype(addr)>) 85 { 86 if (n) 87 { 88 it->second->EthernetInterfaceIntf::defaultGateway6( 89 std::to_string(addr)); 90 } 91 else if (it->second->defaultGateway6() == std::to_string(addr)) 92 { 93 it->second->EthernetInterfaceIntf::defaultGateway6(""); 94 } 95 } 96 else 97 { 98 static_assert(!std::is_same_v<void, decltype(addr)>); 99 } 100 }, 101 std::get<InAddrAny>(*ret)); 102 } 103 104 static void addrhandler(Manager& m, bool n, std::string_view data) 105 { 106 auto info = netlink::addrFromRtm(data); 107 auto it = m.interfacesByIdx.find(info.ifidx); 108 if (it == m.interfacesByIdx.end()) 109 { 110 auto msg = fmt::format("Interface `{}` not found for addr", info.ifidx); 111 log<level::ERR>(msg.c_str(), entry("IFIDX=%u", info.ifidx)); 112 return; 113 } 114 if (n) 115 { 116 it->second->addAddr(info); 117 } 118 else 119 { 120 it->second->addrs.erase(info.ifaddr); 121 } 122 } 123 124 static void handler(Manager& m, const nlmsghdr& hdr, std::string_view data) 125 { 126 if (shouldRefresh(hdr, data) && !refreshObjectTimer->isEnabled()) 127 { 128 refreshObjectTimer->restartOnce(refreshTimeout); 129 } 130 switch (hdr.nlmsg_type) 131 { 132 case RTM_NEWROUTE: 133 rthandler(m, true, data); 134 break; 135 case RTM_DELROUTE: 136 rthandler(m, false, data); 137 break; 138 case RTM_NEWADDR: 139 addrhandler(m, true, data); 140 break; 141 case RTM_DELADDR: 142 addrhandler(m, false, data); 143 break; 144 } 145 } 146 147 static void eventHandler(Manager& m, sdeventplus::source::IO&, int fd, uint32_t) 148 { 149 auto cb = [&](auto&&... args) { 150 return handler(m, std::forward<decltype(args)>(args)...); 151 }; 152 while (receive(fd, cb) > 0) 153 ; 154 } 155 156 static stdplus::ManagedFd makeSock() 157 { 158 using namespace stdplus::fd; 159 160 auto sock = socket(SocketDomain::Netlink, SocketType::Raw, 161 static_cast<stdplus::fd::SocketProto>(NETLINK_ROUTE)); 162 163 sock.fcntlSetfl(sock.fcntlGetfl().set(FileFlag::NonBlock)); 164 165 sockaddr_nl local{}; 166 local.nl_family = AF_NETLINK; 167 local.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | 168 RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NEIGH; 169 bind(sock, local); 170 171 return sock; 172 } 173 174 Server::Server(sdeventplus::Event& event, Manager& manager) : 175 sock(makeSock()), 176 io(event, sock.get(), EPOLLIN | EPOLLET, [&](auto&&... args) { 177 return eventHandler(manager, std::forward<decltype(args)>(args)...); 178 }) 179 { 180 } 181 182 } // namespace netlink 183 } // namespace network 184 } // namespace phosphor 185