blob: 31dbfd1ab39b7fbd36f22901bb4ce9845b065b16 [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
Ratan Gupta16f12882017-09-22 18:26:11 +053024extern std::unique_ptr<phosphor::network::Timer> refreshObjectTimer;
Ratan Guptaa54d8f82017-09-08 17:05:46 +053025
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053026namespace rtnetlink
27{
28
29/* Call Back for the sd event loop */
30static int eventHandler(sd_event_source* es, int fd, uint32_t revents,
31 void* userdata)
32{
33 char buffer[phosphor::network::rtnetlink::BUFSIZE] {};
34 int len {};
35
36 auto netLinkHeader = reinterpret_cast<struct nlmsghdr*>(buffer);
37 while ((len = recv(fd, netLinkHeader,
38 phosphor::network::rtnetlink::BUFSIZE, 0)) > 0)
39 {
40 for (; (NLMSG_OK(netLinkHeader, len)) &&
41 (netLinkHeader->nlmsg_type != NLMSG_DONE);
42 netLinkHeader = NLMSG_NEXT(netLinkHeader, len))
43 {
44 if (netLinkHeader->nlmsg_type == RTM_NEWADDR ||
45 netLinkHeader->nlmsg_type == RTM_DELADDR)
46 {
Ratan Guptaa54d8f82017-09-08 17:05:46 +053047 // starting the timer here to make sure that we don't want
48 // create the child objects multiple times.
Ratan Gupta16f12882017-09-22 18:26:11 +053049 if (refreshObjectTimer->isExpired())
Ratan Guptaa54d8f82017-09-08 17:05:46 +053050 {
51 using namespace std::chrono;
Ratan Gupta16f12882017-09-22 18:26:11 +053052 auto time = duration_cast<microseconds>(refreshTimeout);
Ratan Guptaa54d8f82017-09-08 17:05:46 +053053 // if start timer throws exception then let the application
54 // crash
Ratan Gupta16f12882017-09-22 18:26:11 +053055 refreshObjectTimer->startTimer(time);
Ratan Guptaa54d8f82017-09-08 17:05:46 +053056 } // end if
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053057 } // end if
58
59 } // end for
60
61 } // end while
62
63 return 0;
64}
65
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053066int Server::run()
67{
68 using namespace phosphor::logging;
69
70 struct sockaddr_nl addr {};
71
72 int fd = -1;
73 phosphor::Descriptor smartSock(fd);
74
75 int r {};
76
77 sigset_t ss {};
78
79
80 if (sigemptyset(&ss) < 0 || sigaddset(&ss, SIGTERM) < 0 ||
81 sigaddset(&ss, SIGINT) < 0)
82 {
83 r = -errno;
84 goto finish;
85 }
86 /* Block SIGTERM first, so that the event loop can handle it */
87 if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
88 {
89 r = -errno;
90 goto finish;
91 }
92
93 /* Let's make use of the default handler and "floating"
94 reference features of sd_event_add_signal() */
95
96 r = sd_event_add_signal(eventPtr.get(), NULL, SIGTERM, NULL, NULL);
97 if (r < 0)
98 {
99 goto finish;
100 }
101
102 r = sd_event_add_signal(eventPtr.get(), NULL, SIGINT, NULL, NULL);
103 if (r < 0)
104 {
105 goto finish;
106 }
107
108 fd = socket(PF_NETLINK, SOCK_RAW | SOCK_NONBLOCK, NETLINK_ROUTE);
109 if (fd < 0)
110 {
111 r = -errno;
112 goto finish;
113 }
114
115 smartSock.set(fd);
116 fd = -1;
117
118 memset(&addr, 0, sizeof(addr));
119 addr.nl_family = AF_NETLINK;
Ratan Gupta16f12882017-09-22 18:26:11 +0530120 addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530121
122 if (bind(smartSock(), (struct sockaddr*)&addr, sizeof(addr)) < 0)
123 {
124 r = -errno;
125 goto finish;
126 }
127
128 r = sd_event_add_io(eventPtr.get(), nullptr,
129 smartSock(), EPOLLIN, eventHandler, nullptr);
130 if (r < 0)
131 {
132 goto finish;
133 }
134
135 r = sd_event_loop(eventPtr.get());
136
137finish:
138
139 if (r < 0)
140 {
141 log<level::ERR>("Failure Occured in starting of server:",
142 entry("errno = %d", errno));
143 }
144
145 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
146}
147
148
149} //rtnetlink
150} //network
151} //phosphor