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