1 #include "rtnetlink_server.hpp" 2 3 #include "netlink.hpp" 4 #include "network_manager.hpp" 5 #include "rtnetlink.hpp" 6 7 #include <linux/netlink.h> 8 #include <linux/rtnetlink.h> 9 10 #include <phosphor-logging/log.hpp> 11 #include <stdplus/fd/create.hpp> 12 #include <stdplus/fd/ops.hpp> 13 14 namespace phosphor::network::netlink 15 { 16 17 using phosphor::logging::entry; 18 using phosphor::logging::level; 19 using phosphor::logging::log; 20 21 inline void rthandler(std::string_view data, auto&& cb) 22 { 23 auto ret = gatewayFromRtm(data); 24 if (!ret) 25 { 26 return; 27 } 28 cb(std::get<unsigned>(*ret), std::get<InAddrAny>(*ret)); 29 } 30 31 static void handler(Manager& m, const nlmsghdr& hdr, std::string_view data) 32 { 33 try 34 { 35 switch (hdr.nlmsg_type) 36 { 37 case RTM_NEWLINK: 38 m.addInterface(intfFromRtm(data)); 39 break; 40 case RTM_DELLINK: 41 m.removeInterface(intfFromRtm(data)); 42 break; 43 case RTM_NEWROUTE: 44 rthandler(data, [&](auto ifidx, auto addr) { 45 m.addDefGw(ifidx, addr); 46 }); 47 break; 48 case RTM_DELROUTE: 49 rthandler(data, [&](auto ifidx, auto addr) { 50 m.removeDefGw(ifidx, addr); 51 }); 52 break; 53 case RTM_NEWADDR: 54 m.addAddress(addrFromRtm(data)); 55 break; 56 case RTM_DELADDR: 57 m.removeAddress(addrFromRtm(data)); 58 break; 59 case RTM_NEWNEIGH: 60 m.addNeighbor(neighFromRtm(data)); 61 break; 62 case RTM_DELNEIGH: 63 m.removeNeighbor(neighFromRtm(data)); 64 break; 65 } 66 } 67 catch (const std::exception& e) 68 { 69 auto msg = fmt::format("Failed handling netlink event: {}", e.what()); 70 log<level::ERR>(msg.c_str(), entry("ERROR=%s", e.what())); 71 } 72 } 73 74 static void eventHandler(Manager& m, sdeventplus::source::IO&, int fd, uint32_t) 75 { 76 auto cb = [&](auto&&... args) { 77 return handler(m, std::forward<decltype(args)>(args)...); 78 }; 79 while (receive(fd, cb) > 0) 80 ; 81 } 82 83 static stdplus::ManagedFd makeSock() 84 { 85 using namespace stdplus::fd; 86 87 auto sock = socket(SocketDomain::Netlink, SocketType::Raw, 88 static_cast<stdplus::fd::SocketProto>(NETLINK_ROUTE)); 89 90 sock.fcntlSetfl(sock.fcntlGetfl().set(FileFlag::NonBlock)); 91 92 sockaddr_nl local{}; 93 local.nl_family = AF_NETLINK; 94 local.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | 95 RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NEIGH; 96 bind(sock, local); 97 98 return sock; 99 } 100 101 Server::Server(sdeventplus::Event& event, Manager& manager) : 102 sock(makeSock()), 103 io(event, sock.get(), EPOLLIN | EPOLLET, [&](auto&&... args) { 104 return eventHandler(manager, std::forward<decltype(args)>(args)...); 105 }) 106 { 107 auto cb = [&](const nlmsghdr& hdr, std::string_view data) { 108 handler(manager, hdr, data); 109 }; 110 performRequest(NETLINK_ROUTE, RTM_GETLINK, NLM_F_DUMP, ifinfomsg{}, cb); 111 performRequest(NETLINK_ROUTE, RTM_GETADDR, NLM_F_DUMP, ifaddrmsg{}, cb); 112 performRequest(NETLINK_ROUTE, RTM_GETROUTE, NLM_F_DUMP, rtmsg{}, cb); 113 performRequest(NETLINK_ROUTE, RTM_GETNEIGH, NLM_F_DUMP, ndmsg{}, cb); 114 } 115 116 } // namespace phosphor::network::netlink 117