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