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,
33                           std::string_view data) noexcept
34 {
35     switch (hdr.nlmsg_type)
36     {
37         case RTM_NEWLINK:
38         case RTM_DELLINK:
39         case RTM_NEWADDR:
40         case RTM_DELADDR:
41             return true;
42         case RTM_NEWNEIGH:
43         case RTM_DELNEIGH:
44         {
45             if (data.size() < sizeof(ndmsg))
46             {
47                 return false;
48             }
49             const auto& ndm = *reinterpret_cast<const ndmsg*>(data.data());
50             // We only want to refresh for static neighbors
51             return ndm.ndm_state & NUD_PERMANENT;
52         }
53     }
54     return false;
55 }
56 
57 static void rthandler(Manager& m, bool n, std::string_view data)
58 {
59     auto ret = netlink::gatewayFromRtm(data);
60     if (!ret)
61     {
62         return;
63     }
64     auto ifIdx = std::get<unsigned>(*ret);
65     auto it = m.interfacesByIdx.find(ifIdx);
66     if (it == m.interfacesByIdx.end())
67     {
68         auto msg = fmt::format("Interface `{}` not found for route", ifIdx);
69         log<level::ERR>(msg.c_str(), entry("IFIDX=%u", ifIdx));
70         return;
71     }
72     std::visit(
73         [&](auto addr) {
74             if constexpr (std::is_same_v<in_addr, decltype(addr)>)
75             {
76                 if (n)
77                 {
78                     it->second->EthernetInterfaceIntf::defaultGateway(
79                         std::to_string(addr));
80                 }
81                 else if (it->second->defaultGateway() == std::to_string(addr))
82                 {
83                     it->second->EthernetInterfaceIntf::defaultGateway("");
84                 }
85             }
86             else if constexpr (std::is_same_v<in6_addr, decltype(addr)>)
87             {
88                 if (n)
89                 {
90                     it->second->EthernetInterfaceIntf::defaultGateway6(
91                         std::to_string(addr));
92                 }
93                 else if (it->second->defaultGateway6() == std::to_string(addr))
94                 {
95                     it->second->EthernetInterfaceIntf::defaultGateway6("");
96                 }
97             }
98             else
99             {
100                 static_assert(!std::is_same_v<void, decltype(addr)>);
101             }
102         },
103         std::get<InAddrAny>(*ret));
104 }
105 
106 static void handler(Manager& m, const nlmsghdr& hdr, std::string_view data)
107 {
108     if (shouldRefresh(hdr, data) && !refreshObjectTimer->isEnabled())
109     {
110         refreshObjectTimer->restartOnce(refreshTimeout);
111     }
112     switch (hdr.nlmsg_type)
113     {
114         case RTM_NEWROUTE:
115             rthandler(m, true, data);
116             break;
117         case RTM_DELROUTE:
118             rthandler(m, false, data);
119             break;
120     }
121 }
122 
123 static void eventHandler(Manager& m, sdeventplus::source::IO&, int fd, uint32_t)
124 {
125     auto cb = [&](auto&&... args) {
126         return handler(m, std::forward<decltype(args)>(args)...);
127     };
128     while (receive(fd, cb) > 0)
129         ;
130 }
131 
132 static stdplus::ManagedFd makeSock()
133 {
134     using namespace stdplus::fd;
135 
136     auto sock = socket(SocketDomain::Netlink, SocketType::Raw,
137                        static_cast<stdplus::fd::SocketProto>(NETLINK_ROUTE));
138 
139     sock.fcntlSetfl(sock.fcntlGetfl().set(FileFlag::NonBlock));
140 
141     sockaddr_nl local{};
142     local.nl_family = AF_NETLINK;
143     local.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR |
144                       RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NEIGH;
145     bind(sock, local);
146 
147     return sock;
148 }
149 
150 Server::Server(sdeventplus::Event& event, Manager& manager) :
151     sock(makeSock()),
152     io(event, sock.get(), EPOLLIN | EPOLLET, [&](auto&&... args) {
153         return eventHandler(manager, std::forward<decltype(args)>(args)...);
154     })
155 {
156 }
157 
158 } // namespace netlink
159 } // namespace network
160 } // namespace phosphor
161