1 #include "rtnetlink_server.hpp"
2 
3 #include "types.hpp"
4 #include "util.hpp"
5 
6 #include <linux/netlink.h>
7 #include <linux/rtnetlink.h>
8 #include <net/if.h>
9 #include <netinet/in.h>
10 #include <sys/types.h>
11 #include <systemd/sd-daemon.h>
12 #include <unistd.h>
13 
14 #include <memory>
15 #include <phosphor-logging/elog-errors.hpp>
16 #include <phosphor-logging/log.hpp>
17 #include <string_view>
18 #include <xyz/openbmc_project/Common/error.hpp>
19 
20 namespace phosphor
21 {
22 namespace network
23 {
24 
25 extern std::unique_ptr<Timer> refreshObjectTimer;
26 
27 namespace rtnetlink
28 {
29 
30 static bool shouldRefresh(const struct nlmsghdr& hdr, std::string_view data)
31 {
32     switch (hdr.nlmsg_type)
33     {
34         case RTM_NEWADDR:
35         case RTM_DELADDR:
36         case RTM_NEWROUTE:
37         case RTM_DELROUTE:
38         {
39             return true;
40         }
41         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         }
53     }
54 
55     return false;
56 }
57 
58 /* Call Back for the sd event loop */
59 static int eventHandler(sd_event_source* /*es*/, int fd, uint32_t /*revents*/,
60                         void* /*userdata*/)
61 {
62     char buffer[phosphor::network::rtnetlink::BUFSIZE]{};
63     int len{};
64 
65     auto netLinkHeader = reinterpret_cast<struct nlmsghdr*>(buffer);
66     while ((len = recv(fd, netLinkHeader, phosphor::network::rtnetlink::BUFSIZE,
67                        0)) > 0)
68     {
69         for (; (NLMSG_OK(netLinkHeader, len)) &&
70                (netLinkHeader->nlmsg_type != NLMSG_DONE);
71              netLinkHeader = NLMSG_NEXT(netLinkHeader, len))
72         {
73             std::string_view data(
74                 reinterpret_cast<const char*>(NLMSG_DATA(netLinkHeader)),
75                 netLinkHeader->nlmsg_len - NLMSG_HDRLEN);
76             if (shouldRefresh(*netLinkHeader, data))
77             {
78                 // starting the timer here to make sure that we don't want
79                 // create the child objects multiple times.
80                 if (!refreshObjectTimer->isEnabled())
81                 {
82                     // if start timer throws exception then let the application
83                     // crash
84                     refreshObjectTimer->restartOnce(refreshTimeout);
85                 } // end if
86             }     // end if
87 
88         } // end for
89 
90     } // end while
91 
92     return 0;
93 }
94 
95 Server::Server(EventPtr& eventPtr, const phosphor::Descriptor& smartSock)
96 {
97     using namespace phosphor::logging;
98     using InternalFailure =
99         sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
100     struct sockaddr_nl addr
101     {
102     };
103     int r{};
104 
105     sigset_t ss{};
106     // check that the given socket is valid or not.
107     if (smartSock() < 0)
108     {
109         r = -EBADF;
110         goto finish;
111     }
112 
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 
141     std::memset(&addr, 0, sizeof(addr));
142     addr.nl_family = AF_NETLINK;
143     addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR |
144                      RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NEIGH;
145 
146     if (bind(smartSock(), (struct sockaddr*)&addr, sizeof(addr)) < 0)
147     {
148         r = -errno;
149         goto finish;
150     }
151 
152     r = sd_event_add_io(eventPtr.get(), nullptr, smartSock(), EPOLLIN,
153                         eventHandler, nullptr);
154     if (r < 0)
155     {
156         goto finish;
157     }
158 
159 finish:
160 
161     if (r < 0)
162     {
163         log<level::ERR>("Failure Occurred in starting of server:",
164                         entry("ERRNO=%d", errno));
165         elog<InternalFailure>();
166     }
167 }
168 
169 } // namespace rtnetlink
170 } // namespace network
171 } // namespace phosphor
172