blob: 3722a678c260bc47ce79a18046f13c309c38f391 [file] [log] [blame]
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +05301#include "rtnetlink_server.hpp"
Patrick Venture189d44e2018-07-09 12:30:59 -07002
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +05303#include <linux/netlink.h>
4#include <linux/rtnetlink.h>
Patrick Venture189d44e2018-07-09 12:30:59 -07005#include <netinet/in.h>
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +05306
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +05307#include <memory>
Patrick Venture189d44e2018-07-09 12:30:59 -07008#include <phosphor-logging/elog-errors.hpp>
9#include <phosphor-logging/log.hpp>
William A. Kennington III32eef712022-01-24 17:03:03 -080010#include <stdplus/fd/create.hpp>
11#include <stdplus/fd/ops.hpp>
12#include <stdplus/signal.hpp>
William A. Kennington III08505792019-01-30 16:00:04 -080013#include <string_view>
Patrick Venture189d44e2018-07-09 12:30:59 -070014#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053015
16namespace phosphor
17{
18namespace network
19{
Ratan Guptaa54d8f82017-09-08 17:05:46 +053020
William A. Kennington III3a70fa22018-09-20 18:48:20 -070021extern std::unique_ptr<Timer> refreshObjectTimer;
Ratan Guptaa54d8f82017-09-08 17:05:46 +053022
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053023namespace rtnetlink
24{
25
William A. Kennington III08505792019-01-30 16:00:04 -080026static bool shouldRefresh(const struct nlmsghdr& hdr, std::string_view data)
William A. Kennington IIId2d05942019-01-30 16:04:11 -080027{
28 switch (hdr.nlmsg_type)
29 {
30 case RTM_NEWADDR:
31 case RTM_DELADDR:
William A. Kennington III00506d82019-02-01 21:51:41 -080032 case RTM_NEWROUTE:
33 case RTM_DELROUTE:
William A. Kennington IIId2d05942019-01-30 16:04:11 -080034 {
35 return true;
36 }
William A. Kennington III08505792019-01-30 16:00:04 -080037 case RTM_NEWNEIGH:
38 case RTM_DELNEIGH:
39 {
40 struct ndmsg ndm;
41 if (data.size() < sizeof(ndm))
42 {
43 return false;
44 }
45 memcpy(&ndm, data.data(), sizeof(ndm));
46 // We only want to refresh for static neighbors
47 return ndm.ndm_state & NUD_PERMANENT;
48 }
William A. Kennington IIId2d05942019-01-30 16:04:11 -080049 }
50
51 return false;
52}
53
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053054/* Call Back for the sd event loop */
Manojkiran Edaaa57fa52020-06-13 14:59:53 +053055static int eventHandler(sd_event_source* /*es*/, int fd, uint32_t /*revents*/,
56 void* /*userdata*/)
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053057{
sureshvijayv1205cc102021-09-22 13:05:22 +053058 std::array<char, phosphor::network::rtnetlink::BUFSIZE> buffer = {};
Gunnar Mills57d9c502018-09-14 14:42:34 -050059 int len{};
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053060
sureshvijayv1205cc102021-09-22 13:05:22 +053061 auto netLinkHeader = reinterpret_cast<struct nlmsghdr*>(buffer.data());
62
Gunnar Mills57d9c502018-09-14 14:42:34 -050063 while ((len = recv(fd, netLinkHeader, phosphor::network::rtnetlink::BUFSIZE,
64 0)) > 0)
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053065 {
66 for (; (NLMSG_OK(netLinkHeader, len)) &&
67 (netLinkHeader->nlmsg_type != NLMSG_DONE);
Gunnar Mills57d9c502018-09-14 14:42:34 -050068 netLinkHeader = NLMSG_NEXT(netLinkHeader, len))
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053069 {
William A. Kennington III08505792019-01-30 16:00:04 -080070 std::string_view data(
71 reinterpret_cast<const char*>(NLMSG_DATA(netLinkHeader)),
72 netLinkHeader->nlmsg_len - NLMSG_HDRLEN);
73 if (shouldRefresh(*netLinkHeader, data))
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053074 {
Ratan Guptaa54d8f82017-09-08 17:05:46 +053075 // starting the timer here to make sure that we don't want
76 // create the child objects multiple times.
William A. Kennington IIIcb500dc2018-12-03 15:32:12 -080077 if (!refreshObjectTimer->isEnabled())
Ratan Guptaa54d8f82017-09-08 17:05:46 +053078 {
Ratan Guptaa54d8f82017-09-08 17:05:46 +053079 // if start timer throws exception then let the application
80 // crash
William A. Kennington III3a70fa22018-09-20 18:48:20 -070081 refreshObjectTimer->restartOnce(refreshTimeout);
Ratan Guptaa54d8f82017-09-08 17:05:46 +053082 } // end if
Gunnar Mills57d9c502018-09-14 14:42:34 -050083 } // end if
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053084
85 } // end for
86
sureshvijayv1205cc102021-09-22 13:05:22 +053087 buffer.fill('\0');
88
89 netLinkHeader = reinterpret_cast<struct nlmsghdr*>(buffer.data());
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053090 } // end while
91
92 return 0;
93}
94
William A. Kennington III32eef712022-01-24 17:03:03 -080095static stdplus::ManagedFd makeSock()
96{
97 using namespace stdplus::fd;
98
99 auto sock = socket(SocketDomain::Netlink, SocketType::Raw,
100 static_cast<stdplus::fd::SocketProto>(NETLINK_ROUTE));
101
102 sock.fcntlSetfl(sock.fcntlGetfl().set(FileFlag::NonBlock));
103
104 sockaddr_nl local{};
105 local.nl_family = AF_NETLINK;
106 local.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR |
107 RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NEIGH;
108 bind(sock, local);
109
110 return sock;
111}
112
113Server::Server(EventPtr& eventPtr) : sock(makeSock())
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530114{
115 using namespace phosphor::logging;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500116 using InternalFailure =
117 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500118 int r{};
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530119
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530120 /* Let's make use of the default handler and "floating"
121 reference features of sd_event_add_signal() */
122
William A. Kennington III32eef712022-01-24 17:03:03 -0800123 stdplus::signal::block(SIGTERM);
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530124 r = sd_event_add_signal(eventPtr.get(), NULL, SIGTERM, NULL, NULL);
125 if (r < 0)
126 {
127 goto finish;
128 }
129
William A. Kennington III32eef712022-01-24 17:03:03 -0800130 stdplus::signal::block(SIGINT);
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530131 r = sd_event_add_signal(eventPtr.get(), NULL, SIGINT, NULL, NULL);
132 if (r < 0)
133 {
134 goto finish;
135 }
136
William A. Kennington III32eef712022-01-24 17:03:03 -0800137 r = sd_event_add_io(eventPtr.get(), nullptr, sock.get(), EPOLLIN,
Gunnar Mills57d9c502018-09-14 14:42:34 -0500138 eventHandler, nullptr);
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530139 if (r < 0)
140 {
141 goto finish;
142 }
143
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530144finish:
145
146 if (r < 0)
147 {
Gunnar Millsd75f0492017-10-25 20:33:32 -0500148 log<level::ERR>("Failure Occurred in starting of server:",
Gunnar Millsfc7df192017-10-19 16:11:05 -0500149 entry("ERRNO=%d", errno));
Vishwanatha Subbanna18891c62017-10-17 15:22:46 +0530150 elog<InternalFailure>();
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530151 }
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530152}
153
Gunnar Mills57d9c502018-09-14 14:42:34 -0500154} // namespace rtnetlink
155} // namespace network
156} // namespace phosphor