blob: 2a0ab381654d9323a959b20d3e58b4479602922a [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 III5f165dc2022-10-24 15:58:55 -070032static bool shouldRefresh(const struct nlmsghdr& hdr,
33 std::string_view data) noexcept
William A. Kennington IIId2d05942019-01-30 16:04:11 -080034{
35 switch (hdr.nlmsg_type)
36 {
William A. Kennington III226cada2022-10-28 16:33:11 -070037 case RTM_NEWLINK:
38 case RTM_DELLINK:
William A. Kennington IIId2d05942019-01-30 16:04:11 -080039 return true;
William A. Kennington III08505792019-01-30 16:00:04 -080040 case RTM_NEWNEIGH:
41 case RTM_DELNEIGH:
42 {
William A. Kennington IIIc8e992f2022-10-24 16:15:32 -070043 if (data.size() < sizeof(ndmsg))
William A. Kennington III08505792019-01-30 16:00:04 -080044 {
45 return false;
46 }
William A. Kennington IIIc8e992f2022-10-24 16:15:32 -070047 const auto& ndm = *reinterpret_cast<const ndmsg*>(data.data());
William A. Kennington III08505792019-01-30 16:00:04 -080048 // We only want to refresh for static neighbors
49 return ndm.ndm_state & NUD_PERMANENT;
50 }
William A. Kennington IIId2d05942019-01-30 16:04:11 -080051 }
William A. Kennington IIId2d05942019-01-30 16:04:11 -080052 return false;
53}
54
William A. Kennington III71590bf2022-10-31 14:14:16 -070055static void rthandler(Manager& m, bool n, std::string_view data)
56{
57 auto ret = netlink::gatewayFromRtm(data);
58 if (!ret)
59 {
60 return;
61 }
62 auto ifIdx = std::get<unsigned>(*ret);
63 auto it = m.interfacesByIdx.find(ifIdx);
64 if (it == m.interfacesByIdx.end())
65 {
66 auto msg = fmt::format("Interface `{}` not found for route", ifIdx);
67 log<level::ERR>(msg.c_str(), entry("IFIDX=%u", ifIdx));
68 return;
69 }
70 std::visit(
71 [&](auto addr) {
72 if constexpr (std::is_same_v<in_addr, decltype(addr)>)
73 {
74 if (n)
75 {
76 it->second->EthernetInterfaceIntf::defaultGateway(
77 std::to_string(addr));
78 }
79 else if (it->second->defaultGateway() == std::to_string(addr))
80 {
81 it->second->EthernetInterfaceIntf::defaultGateway("");
82 }
83 }
84 else if constexpr (std::is_same_v<in6_addr, decltype(addr)>)
85 {
86 if (n)
87 {
88 it->second->EthernetInterfaceIntf::defaultGateway6(
89 std::to_string(addr));
90 }
91 else if (it->second->defaultGateway6() == std::to_string(addr))
92 {
93 it->second->EthernetInterfaceIntf::defaultGateway6("");
94 }
95 }
96 else
97 {
98 static_assert(!std::is_same_v<void, decltype(addr)>);
99 }
100 },
101 std::get<InAddrAny>(*ret));
102}
103
William A. Kennington IIId6f53402022-11-07 14:48:53 -0800104static void addrhandler(Manager& m, bool n, std::string_view data)
105{
106 auto info = netlink::addrFromRtm(data);
107 auto it = m.interfacesByIdx.find(info.ifidx);
108 if (it == m.interfacesByIdx.end())
109 {
110 auto msg = fmt::format("Interface `{}` not found for addr", info.ifidx);
111 log<level::ERR>(msg.c_str(), entry("IFIDX=%u", info.ifidx));
112 return;
113 }
114 if (n)
115 {
116 it->second->addAddr(info);
117 }
118 else
119 {
120 it->second->addrs.erase(info.ifaddr);
121 }
122}
123
William A. Kennington III71590bf2022-10-31 14:14:16 -0700124static void handler(Manager& m, const nlmsghdr& hdr, std::string_view data)
William A. Kennington III5f165dc2022-10-24 15:58:55 -0700125{
126 if (shouldRefresh(hdr, data) && !refreshObjectTimer->isEnabled())
127 {
128 refreshObjectTimer->restartOnce(refreshTimeout);
129 }
William A. Kennington III71590bf2022-10-31 14:14:16 -0700130 switch (hdr.nlmsg_type)
131 {
132 case RTM_NEWROUTE:
133 rthandler(m, true, data);
134 break;
135 case RTM_DELROUTE:
136 rthandler(m, false, data);
137 break;
William A. Kennington IIId6f53402022-11-07 14:48:53 -0800138 case RTM_NEWADDR:
139 addrhandler(m, true, data);
140 break;
141 case RTM_DELADDR:
142 addrhandler(m, false, data);
143 break;
William A. Kennington III71590bf2022-10-31 14:14:16 -0700144 }
William A. Kennington III5f165dc2022-10-24 15:58:55 -0700145}
146
William A. Kennington III71590bf2022-10-31 14:14:16 -0700147static void eventHandler(Manager& m, sdeventplus::source::IO&, int fd, uint32_t)
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530148{
William A. Kennington III71590bf2022-10-31 14:14:16 -0700149 auto cb = [&](auto&&... args) {
150 return handler(m, std::forward<decltype(args)>(args)...);
151 };
152 while (receive(fd, cb) > 0)
William A. Kennington III29418ef2022-11-07 22:59:47 -0800153 ;
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530154}
155
William A. Kennington III32eef712022-01-24 17:03:03 -0800156static stdplus::ManagedFd makeSock()
157{
158 using namespace stdplus::fd;
159
160 auto sock = socket(SocketDomain::Netlink, SocketType::Raw,
161 static_cast<stdplus::fd::SocketProto>(NETLINK_ROUTE));
162
163 sock.fcntlSetfl(sock.fcntlGetfl().set(FileFlag::NonBlock));
164
165 sockaddr_nl local{};
166 local.nl_family = AF_NETLINK;
William A. Kennington III226cada2022-10-28 16:33:11 -0700167 local.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR |
William A. Kennington III32eef712022-01-24 17:03:03 -0800168 RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NEIGH;
169 bind(sock, local);
170
171 return sock;
172}
173
William A. Kennington III71590bf2022-10-31 14:14:16 -0700174Server::Server(sdeventplus::Event& event, Manager& manager) :
175 sock(makeSock()),
176 io(event, sock.get(), EPOLLIN | EPOLLET, [&](auto&&... args) {
177 return eventHandler(manager, std::forward<decltype(args)>(args)...);
178 })
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530179{
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530180}
181
William A. Kennington III5f165dc2022-10-24 15:58:55 -0700182} // namespace netlink
Gunnar Mills57d9c502018-09-14 14:42:34 -0500183} // namespace network
184} // namespace phosphor