blob: 8e636a17a3090e174be14a962b0255e464df051b [file] [log] [blame]
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +05301#include "rtnetlink_server.hpp"
Ratan Guptaa54d8f82017-09-08 17:05:46 +05302#include "timer.hpp"
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +05303#include "types.hpp"
4#include "util.hpp"
5
6
7#include <netinet/in.h>
8#include <linux/netlink.h>
9#include <linux/rtnetlink.h>
10#include <net/if.h>
11#include <sys/types.h>
12#include <systemd/sd-daemon.h>
13#include <unistd.h>
14
15#include <phosphor-logging/log.hpp>
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053016
17#include <memory>
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053018
19namespace phosphor
20{
21namespace network
22{
Ratan Guptaa54d8f82017-09-08 17:05:46 +053023
24extern std::unique_ptr<phosphor::network::Timer> refreshTimer;
25
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053026namespace rtnetlink
27{
28
Ratan Guptaa54d8f82017-09-08 17:05:46 +053029using namespace std::chrono_literals;
30constexpr auto networkChangeTimeout = 1s; //seconds
31
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053032/* Call Back for the sd event loop */
33static int eventHandler(sd_event_source* es, int fd, uint32_t revents,
34 void* userdata)
35{
36 char buffer[phosphor::network::rtnetlink::BUFSIZE] {};
37 int len {};
38
39 auto netLinkHeader = reinterpret_cast<struct nlmsghdr*>(buffer);
40 while ((len = recv(fd, netLinkHeader,
41 phosphor::network::rtnetlink::BUFSIZE, 0)) > 0)
42 {
43 for (; (NLMSG_OK(netLinkHeader, len)) &&
44 (netLinkHeader->nlmsg_type != NLMSG_DONE);
45 netLinkHeader = NLMSG_NEXT(netLinkHeader, len))
46 {
47 if (netLinkHeader->nlmsg_type == RTM_NEWADDR ||
48 netLinkHeader->nlmsg_type == RTM_DELADDR)
49 {
Ratan Guptaa54d8f82017-09-08 17:05:46 +053050 // starting the timer here to make sure that we don't want
51 // create the child objects multiple times.
52 if (refreshTimer->isExpired())
53 {
54 using namespace std::chrono;
55 auto time = duration_cast<microseconds>(networkChangeTimeout);
56 // if start timer throws exception then let the application
57 // crash
58 refreshTimer->startTimer(time);
59 } // end if
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053060 } // end if
61
62 } // end for
63
64 } // end while
65
66 return 0;
67}
68
69
70int Server::run()
71{
72 using namespace phosphor::logging;
73
74 struct sockaddr_nl addr {};
75
76 int fd = -1;
77 phosphor::Descriptor smartSock(fd);
78
79 int r {};
80
81 sigset_t ss {};
82
83
84 if (sigemptyset(&ss) < 0 || sigaddset(&ss, SIGTERM) < 0 ||
85 sigaddset(&ss, SIGINT) < 0)
86 {
87 r = -errno;
88 goto finish;
89 }
90 /* Block SIGTERM first, so that the event loop can handle it */
91 if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
92 {
93 r = -errno;
94 goto finish;
95 }
96
97 /* Let's make use of the default handler and "floating"
98 reference features of sd_event_add_signal() */
99
100 r = sd_event_add_signal(eventPtr.get(), NULL, SIGTERM, NULL, NULL);
101 if (r < 0)
102 {
103 goto finish;
104 }
105
106 r = sd_event_add_signal(eventPtr.get(), NULL, SIGINT, NULL, NULL);
107 if (r < 0)
108 {
109 goto finish;
110 }
111
112 fd = socket(PF_NETLINK, SOCK_RAW | SOCK_NONBLOCK, NETLINK_ROUTE);
113 if (fd < 0)
114 {
115 r = -errno;
116 goto finish;
117 }
118
119 smartSock.set(fd);
120 fd = -1;
121
122 memset(&addr, 0, sizeof(addr));
123 addr.nl_family = AF_NETLINK;
124 addr.nl_groups = RTMGRP_IPV4_IFADDR;
125
126 if (bind(smartSock(), (struct sockaddr*)&addr, sizeof(addr)) < 0)
127 {
128 r = -errno;
129 goto finish;
130 }
131
132 r = sd_event_add_io(eventPtr.get(), nullptr,
133 smartSock(), EPOLLIN, eventHandler, nullptr);
134 if (r < 0)
135 {
136 goto finish;
137 }
138
139 r = sd_event_loop(eventPtr.get());
140
141finish:
142
143 if (r < 0)
144 {
145 log<level::ERR>("Failure Occured in starting of server:",
146 entry("errno = %d", errno));
147 }
148
149 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
150}
151
152
153} //rtnetlink
154} //network
155} //phosphor