blob: 1c4fd53514f8a62fbfa1d5483bacb8f2ad5ae534 [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 "types.hpp"
4#include "util.hpp"
5
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +05306#include <linux/netlink.h>
7#include <linux/rtnetlink.h>
8#include <net/if.h>
Patrick Venture189d44e2018-07-09 12:30:59 -07009#include <netinet/in.h>
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053010#include <sys/types.h>
11#include <systemd/sd-daemon.h>
12#include <unistd.h>
13
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053014#include <memory>
Patrick Venture189d44e2018-07-09 12:30:59 -070015#include <phosphor-logging/elog-errors.hpp>
16#include <phosphor-logging/log.hpp>
William A. Kennington III08505792019-01-30 16:00:04 -080017#include <string_view>
Patrick Venture189d44e2018-07-09 12:30:59 -070018#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053019
20namespace phosphor
21{
22namespace network
23{
Ratan Guptaa54d8f82017-09-08 17:05:46 +053024
William A. Kennington III3a70fa22018-09-20 18:48:20 -070025extern std::unique_ptr<Timer> refreshObjectTimer;
Ratan Guptaa54d8f82017-09-08 17:05:46 +053026
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053027namespace rtnetlink
28{
29
William A. Kennington III08505792019-01-30 16:00:04 -080030static bool shouldRefresh(const struct nlmsghdr& hdr, std::string_view data)
William A. Kennington IIId2d05942019-01-30 16:04:11 -080031{
32 switch (hdr.nlmsg_type)
33 {
34 case RTM_NEWADDR:
35 case RTM_DELADDR:
William A. Kennington III00506d82019-02-01 21:51:41 -080036 case RTM_NEWROUTE:
37 case RTM_DELROUTE:
William A. Kennington IIId2d05942019-01-30 16:04:11 -080038 {
39 return true;
40 }
William A. Kennington III08505792019-01-30 16:00:04 -080041 case RTM_NEWNEIGH:
42 case RTM_DELNEIGH:
43 {
44 struct ndmsg ndm;
45 if (data.size() < sizeof(ndm))
46 {
47 return false;
48 }
49 memcpy(&ndm, data.data(), sizeof(ndm));
50 // We only want to refresh for static neighbors
51 return ndm.ndm_state & NUD_PERMANENT;
52 }
William A. Kennington IIId2d05942019-01-30 16:04:11 -080053 }
54
55 return false;
56}
57
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053058/* Call Back for the sd event loop */
59static int eventHandler(sd_event_source* es, int fd, uint32_t revents,
60 void* userdata)
61{
Gunnar Mills57d9c502018-09-14 14:42:34 -050062 char buffer[phosphor::network::rtnetlink::BUFSIZE]{};
63 int len{};
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053064
65 auto netLinkHeader = reinterpret_cast<struct nlmsghdr*>(buffer);
Gunnar Mills57d9c502018-09-14 14:42:34 -050066 while ((len = recv(fd, netLinkHeader, phosphor::network::rtnetlink::BUFSIZE,
67 0)) > 0)
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053068 {
69 for (; (NLMSG_OK(netLinkHeader, len)) &&
70 (netLinkHeader->nlmsg_type != NLMSG_DONE);
Gunnar Mills57d9c502018-09-14 14:42:34 -050071 netLinkHeader = NLMSG_NEXT(netLinkHeader, len))
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053072 {
William A. Kennington III08505792019-01-30 16:00:04 -080073 std::string_view data(
74 reinterpret_cast<const char*>(NLMSG_DATA(netLinkHeader)),
75 netLinkHeader->nlmsg_len - NLMSG_HDRLEN);
76 if (shouldRefresh(*netLinkHeader, data))
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053077 {
Ratan Guptaa54d8f82017-09-08 17:05:46 +053078 // starting the timer here to make sure that we don't want
79 // create the child objects multiple times.
William A. Kennington IIIcb500dc2018-12-03 15:32:12 -080080 if (!refreshObjectTimer->isEnabled())
Ratan Guptaa54d8f82017-09-08 17:05:46 +053081 {
Ratan Guptaa54d8f82017-09-08 17:05:46 +053082 // if start timer throws exception then let the application
83 // crash
William A. Kennington III3a70fa22018-09-20 18:48:20 -070084 refreshObjectTimer->restartOnce(refreshTimeout);
Ratan Guptaa54d8f82017-09-08 17:05:46 +053085 } // end if
Gunnar Mills57d9c502018-09-14 14:42:34 -050086 } // end if
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053087
88 } // end for
89
90 } // end while
91
92 return 0;
93}
94
Ratan Guptaf6657382017-11-10 17:58:17 +053095Server::Server(EventPtr& eventPtr, const phosphor::Descriptor& smartSock)
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053096{
97 using namespace phosphor::logging;
Gunnar Mills57d9c502018-09-14 14:42:34 -050098 using InternalFailure =
99 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
100 struct sockaddr_nl addr
101 {
102 };
103 int r{};
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530104
Gunnar Mills57d9c502018-09-14 14:42:34 -0500105 sigset_t ss{};
Ratan Guptaf6657382017-11-10 17:58:17 +0530106 // check that the given socket is valid or not.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500107 if (smartSock() < 0)
Ratan Guptaf6657382017-11-10 17:58:17 +0530108 {
109 r = -EBADF;
110 goto finish;
111 }
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530112
113 if (sigemptyset(&ss) < 0 || sigaddset(&ss, SIGTERM) < 0 ||
114 sigaddset(&ss, SIGINT) < 0)
115 {
116 r = -errno;
117 goto finish;
118 }
119 /* Block SIGTERM first, so that the event loop can handle it */
120 if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
121 {
122 r = -errno;
123 goto finish;
124 }
125
126 /* Let's make use of the default handler and "floating"
127 reference features of sd_event_add_signal() */
128
129 r = sd_event_add_signal(eventPtr.get(), NULL, SIGTERM, NULL, NULL);
130 if (r < 0)
131 {
132 goto finish;
133 }
134
135 r = sd_event_add_signal(eventPtr.get(), NULL, SIGINT, NULL, NULL);
136 if (r < 0)
137 {
138 goto finish;
139 }
140
Patrick Venture836c91d2018-09-11 17:36:03 -0700141 std::memset(&addr, 0, sizeof(addr));
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530142 addr.nl_family = AF_NETLINK;
William A. Kennington III00506d82019-02-01 21:51:41 -0800143 addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR |
William A. Kennington III08505792019-01-30 16:00:04 -0800144 RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NEIGH;
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530145
146 if (bind(smartSock(), (struct sockaddr*)&addr, sizeof(addr)) < 0)
147 {
148 r = -errno;
149 goto finish;
150 }
151
Gunnar Mills57d9c502018-09-14 14:42:34 -0500152 r = sd_event_add_io(eventPtr.get(), nullptr, smartSock(), EPOLLIN,
153 eventHandler, nullptr);
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530154 if (r < 0)
155 {
156 goto finish;
157 }
158
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530159finish:
160
161 if (r < 0)
162 {
Gunnar Millsd75f0492017-10-25 20:33:32 -0500163 log<level::ERR>("Failure Occurred in starting of server:",
Gunnar Millsfc7df192017-10-19 16:11:05 -0500164 entry("ERRNO=%d", errno));
Vishwanatha Subbanna18891c62017-10-17 15:22:46 +0530165 elog<InternalFailure>();
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530166 }
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530167}
168
Gunnar Mills57d9c502018-09-14 14:42:34 -0500169} // namespace rtnetlink
170} // namespace network
171} // namespace phosphor