blob: 46453676a9b0ebb51954f107dd87cb953e701fd1 [file] [log] [blame]
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +05301#include "rtnetlink_server.hpp"
Patrick Venture189d44e2018-07-09 12:30:59 -07002
William A. Kennington III5f165dc2022-10-24 15:58:55 -07003#include "netlink.hpp"
William A. Kennington III71590bf2022-10-31 14:14:16 -07004#include "network_manager.hpp"
5#include "rtnetlink.hpp"
William A. Kennington III217bb3f2022-09-29 13:43:13 -07006#include "types.hpp"
7
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +05308#include <linux/netlink.h>
9#include <linux/rtnetlink.h>
Patrick Venture189d44e2018-07-09 12:30:59 -070010#include <netinet/in.h>
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053011
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053012#include <memory>
William A. Kennington III71590bf2022-10-31 14:14:16 -070013#include <phosphor-logging/log.hpp>
William A. Kennington III32eef712022-01-24 17:03:03 -080014#include <stdplus/fd/create.hpp>
15#include <stdplus/fd/ops.hpp>
William A. Kennington III08505792019-01-30 16:00:04 -080016#include <string_view>
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053017
18namespace phosphor
19{
20namespace network
21{
Ratan Guptaa54d8f82017-09-08 17:05:46 +053022
William A. Kennington III3a70fa22018-09-20 18:48:20 -070023extern std::unique_ptr<Timer> refreshObjectTimer;
Ratan Guptaa54d8f82017-09-08 17:05:46 +053024
William A. Kennington III5f165dc2022-10-24 15:58:55 -070025namespace netlink
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053026{
27
William A. Kennington III71590bf2022-10-31 14:14:16 -070028using phosphor::logging::entry;
29using phosphor::logging::level;
30using phosphor::logging::log;
31
William A. Kennington IIIbc2502c2022-11-07 16:31:54 -080032static bool shouldRefresh(const struct nlmsghdr& hdr, std::string_view) noexcept
William A. Kennington IIId2d05942019-01-30 16:04:11 -080033{
34 switch (hdr.nlmsg_type)
35 {
William A. Kennington III226cada2022-10-28 16:33:11 -070036 case RTM_NEWLINK:
37 case RTM_DELLINK:
William A. Kennington IIId2d05942019-01-30 16:04:11 -080038 return true;
William A. Kennington IIId2d05942019-01-30 16:04:11 -080039 }
William A. Kennington IIId2d05942019-01-30 16:04:11 -080040 return false;
41}
42
William A. Kennington III71590bf2022-10-31 14:14:16 -070043static void rthandler(Manager& m, bool n, std::string_view data)
44{
45 auto ret = netlink::gatewayFromRtm(data);
46 if (!ret)
47 {
48 return;
49 }
50 auto ifIdx = std::get<unsigned>(*ret);
51 auto it = m.interfacesByIdx.find(ifIdx);
52 if (it == m.interfacesByIdx.end())
53 {
54 auto msg = fmt::format("Interface `{}` not found for route", ifIdx);
55 log<level::ERR>(msg.c_str(), entry("IFIDX=%u", ifIdx));
56 return;
57 }
58 std::visit(
59 [&](auto addr) {
60 if constexpr (std::is_same_v<in_addr, decltype(addr)>)
61 {
62 if (n)
63 {
64 it->second->EthernetInterfaceIntf::defaultGateway(
65 std::to_string(addr));
66 }
67 else if (it->second->defaultGateway() == std::to_string(addr))
68 {
69 it->second->EthernetInterfaceIntf::defaultGateway("");
70 }
71 }
72 else if constexpr (std::is_same_v<in6_addr, decltype(addr)>)
73 {
74 if (n)
75 {
76 it->second->EthernetInterfaceIntf::defaultGateway6(
77 std::to_string(addr));
78 }
79 else if (it->second->defaultGateway6() == std::to_string(addr))
80 {
81 it->second->EthernetInterfaceIntf::defaultGateway6("");
82 }
83 }
84 else
85 {
86 static_assert(!std::is_same_v<void, decltype(addr)>);
87 }
88 },
89 std::get<InAddrAny>(*ret));
90}
91
William A. Kennington IIId6f53402022-11-07 14:48:53 -080092static void addrhandler(Manager& m, bool n, std::string_view data)
93{
94 auto info = netlink::addrFromRtm(data);
95 auto it = m.interfacesByIdx.find(info.ifidx);
96 if (it == m.interfacesByIdx.end())
97 {
98 auto msg = fmt::format("Interface `{}` not found for addr", info.ifidx);
99 log<level::ERR>(msg.c_str(), entry("IFIDX=%u", info.ifidx));
100 return;
101 }
102 if (n)
103 {
104 it->second->addAddr(info);
105 }
106 else
107 {
108 it->second->addrs.erase(info.ifaddr);
109 }
110}
111
William A. Kennington IIIbc2502c2022-11-07 16:31:54 -0800112static void neighhandler(Manager& m, bool n, std::string_view data)
113{
114 auto info = netlink::neighFromRtm(data);
115 auto it = m.interfacesByIdx.find(info.ifidx);
116 if (it == m.interfacesByIdx.end())
117 {
118 auto msg = fmt::format("Interface `{}` not found for addr", info.ifidx);
119 log<level::ERR>(msg.c_str(), entry("IFIDX=%u", info.ifidx));
120 return;
121 }
122 if (n)
123 {
124 it->second->addStaticNeigh(info);
125 }
126 else
127 {
128 it->second->staticNeighbors.erase(info.addr);
129 }
130}
131
William A. Kennington III71590bf2022-10-31 14:14:16 -0700132static void handler(Manager& m, const nlmsghdr& hdr, std::string_view data)
William A. Kennington III5f165dc2022-10-24 15:58:55 -0700133{
134 if (shouldRefresh(hdr, data) && !refreshObjectTimer->isEnabled())
135 {
136 refreshObjectTimer->restartOnce(refreshTimeout);
137 }
William A. Kennington IIIc0fdaaf2022-11-07 16:44:56 -0800138 try
William A. Kennington III71590bf2022-10-31 14:14:16 -0700139 {
William A. Kennington IIIc0fdaaf2022-11-07 16:44:56 -0800140 switch (hdr.nlmsg_type)
141 {
142 case RTM_NEWROUTE:
143 rthandler(m, true, data);
144 break;
145 case RTM_DELROUTE:
146 rthandler(m, false, data);
147 break;
148 case RTM_NEWADDR:
149 addrhandler(m, true, data);
150 break;
151 case RTM_DELADDR:
152 addrhandler(m, false, data);
153 break;
154 case RTM_NEWNEIGH:
155 neighhandler(m, true, data);
156 break;
157 case RTM_DELNEIGH:
158 neighhandler(m, false, data);
159 break;
160 }
161 }
162 catch (const std::exception& e)
163 {
164 auto msg = fmt::format("Failed parsing netlink event: {}", e.what());
165 log<level::ERR>(msg.c_str());
William A. Kennington III71590bf2022-10-31 14:14:16 -0700166 }
William A. Kennington III5f165dc2022-10-24 15:58:55 -0700167}
168
William A. Kennington III71590bf2022-10-31 14:14:16 -0700169static void eventHandler(Manager& m, sdeventplus::source::IO&, int fd, uint32_t)
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530170{
William A. Kennington III71590bf2022-10-31 14:14:16 -0700171 auto cb = [&](auto&&... args) {
172 return handler(m, std::forward<decltype(args)>(args)...);
173 };
174 while (receive(fd, cb) > 0)
William A. Kennington III29418ef2022-11-07 22:59:47 -0800175 ;
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530176}
177
William A. Kennington III32eef712022-01-24 17:03:03 -0800178static stdplus::ManagedFd makeSock()
179{
180 using namespace stdplus::fd;
181
182 auto sock = socket(SocketDomain::Netlink, SocketType::Raw,
183 static_cast<stdplus::fd::SocketProto>(NETLINK_ROUTE));
184
185 sock.fcntlSetfl(sock.fcntlGetfl().set(FileFlag::NonBlock));
186
187 sockaddr_nl local{};
188 local.nl_family = AF_NETLINK;
William A. Kennington III226cada2022-10-28 16:33:11 -0700189 local.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR |
William A. Kennington III32eef712022-01-24 17:03:03 -0800190 RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NEIGH;
191 bind(sock, local);
192
193 return sock;
194}
195
William A. Kennington III71590bf2022-10-31 14:14:16 -0700196Server::Server(sdeventplus::Event& event, Manager& manager) :
197 sock(makeSock()),
198 io(event, sock.get(), EPOLLIN | EPOLLET, [&](auto&&... args) {
199 return eventHandler(manager, std::forward<decltype(args)>(args)...);
200 })
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530201{
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530202}
203
William A. Kennington III5f165dc2022-10-24 15:58:55 -0700204} // namespace netlink
Gunnar Mills57d9c502018-09-14 14:42:34 -0500205} // namespace network
206} // namespace phosphor