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