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, std::string_view) noexcept 33 { 34 switch (hdr.nlmsg_type) 35 { 36 case RTM_NEWLINK: 37 case RTM_DELLINK: 38 return true; 39 } 40 return false; 41 } 42 43 inline void rthandler(std::string_view data, auto&& cb) 44 { 45 auto ret = gatewayFromRtm(data); 46 if (!ret) 47 { 48 return; 49 } 50 cb(std::get<unsigned>(*ret), std::get<InAddrAny>(*ret)); 51 } 52 53 static void handler(Manager& m, const nlmsghdr& hdr, std::string_view data) 54 { 55 if (shouldRefresh(hdr, data) && !refreshObjectTimer->isEnabled()) 56 { 57 refreshObjectTimer->restartOnce(refreshTimeout); 58 } 59 try 60 { 61 switch (hdr.nlmsg_type) 62 { 63 case RTM_NEWROUTE: 64 rthandler(data, [&](auto ifidx, auto addr) { 65 m.addDefGw(ifidx, addr); 66 }); 67 break; 68 case RTM_DELROUTE: 69 rthandler(data, [&](auto ifidx, auto addr) { 70 m.removeDefGw(ifidx, addr); 71 }); 72 break; 73 case RTM_NEWADDR: 74 m.addAddress(addrFromRtm(data)); 75 break; 76 case RTM_DELADDR: 77 m.removeAddress(addrFromRtm(data)); 78 break; 79 case RTM_NEWNEIGH: 80 m.addNeighbor(neighFromRtm(data)); 81 break; 82 case RTM_DELNEIGH: 83 m.removeNeighbor(neighFromRtm(data)); 84 break; 85 } 86 } 87 catch (const std::exception& e) 88 { 89 auto msg = fmt::format("Failed handling netlink event: {}", e.what()); 90 log<level::ERR>(msg.c_str(), entry("ERROR=%s", e.what())); 91 } 92 } 93 94 static void eventHandler(Manager& m, sdeventplus::source::IO&, int fd, uint32_t) 95 { 96 auto cb = [&](auto&&... args) { 97 return handler(m, std::forward<decltype(args)>(args)...); 98 }; 99 while (receive(fd, cb) > 0) 100 ; 101 } 102 103 static stdplus::ManagedFd makeSock() 104 { 105 using namespace stdplus::fd; 106 107 auto sock = socket(SocketDomain::Netlink, SocketType::Raw, 108 static_cast<stdplus::fd::SocketProto>(NETLINK_ROUTE)); 109 110 sock.fcntlSetfl(sock.fcntlGetfl().set(FileFlag::NonBlock)); 111 112 sockaddr_nl local{}; 113 local.nl_family = AF_NETLINK; 114 local.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | 115 RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NEIGH; 116 bind(sock, local); 117 118 return sock; 119 } 120 121 Server::Server(sdeventplus::Event& event, Manager& manager) : 122 sock(makeSock()), 123 io(event, sock.get(), EPOLLIN | EPOLLET, [&](auto&&... args) { 124 return eventHandler(manager, std::forward<decltype(args)>(args)...); 125 }) 126 { 127 } 128 129 } // namespace netlink 130 } // namespace network 131 } // namespace phosphor 132