blob: 02c84fb535e56305700b91565275f7e208f54a2a [file] [log] [blame]
Davide Pesavento9a8bae52016-02-24 20:33:08 +01001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento88a0d812017-08-19 21:31:42 -04002/*
Davide Pesavento2bf35a62017-04-02 00:41:06 -04003 * Copyright (c) 2013-2017 Regents of the University of California.
Davide Pesavento9a8bae52016-02-24 20:33:08 +01004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Davide Pesavento2bf35a62017-04-02 00:41:06 -040020 *
21 * @author Davide Pesavento <davide.pesavento@lip6.fr>
Davide Pesavento9a8bae52016-02-24 20:33:08 +010022 */
23
Davide Pesavento9a8bae52016-02-24 20:33:08 +010024#include "network-monitor-impl-rtnl.hpp"
Davide Pesavento2bf35a62017-04-02 00:41:06 -040025#include "linux-if-constants.hpp"
Davide Pesavento2bf35a62017-04-02 00:41:06 -040026#include "../network-address.hpp"
27#include "../network-interface.hpp"
Junxiao Shi25467942017-06-30 02:53:14 +000028#include "../../util/logger.hpp"
29#include "../../util/time.hpp"
Davide Pesavento9a8bae52016-02-24 20:33:08 +010030
Davide Pesavento2bf35a62017-04-02 00:41:06 -040031#include <boost/asio/write.hpp>
Davide Pesavento9a8bae52016-02-24 20:33:08 +010032
33#include <cerrno>
Davide Pesavento2bf35a62017-04-02 00:41:06 -040034#include <cstdlib>
35#include <net/if_arp.h>
36#include <sys/socket.h>
37
38NDN_LOG_INIT(ndn.NetworkMonitor);
Davide Pesavento9a8bae52016-02-24 20:33:08 +010039
40namespace ndn {
Junxiao Shi25467942017-06-30 02:53:14 +000041namespace net {
Davide Pesavento9a8bae52016-02-24 20:33:08 +010042
Junxiao Shi2dc416d2017-07-03 04:46:16 +000043NetworkMonitorImplRtnl::NetworkMonitorImplRtnl(boost::asio::io_service& io)
44 : m_socket(make_shared<boost::asio::posix::stream_descriptor>(io))
Davide Pesavento2bf35a62017-04-02 00:41:06 -040045 , m_pid(0)
46 , m_sequenceNo(static_cast<uint32_t>(time::system_clock::now().time_since_epoch().count()))
47 , m_isEnumeratingLinks(false)
48 , m_isEnumeratingAddresses(false)
Davide Pesavento9a8bae52016-02-24 20:33:08 +010049{
Davide Pesavento2bf35a62017-04-02 00:41:06 -040050 initSocket();
51 asyncRead();
Davide Pesavento9a8bae52016-02-24 20:33:08 +010052
Davide Pesavento2bf35a62017-04-02 00:41:06 -040053 NDN_LOG_TRACE("enumerating links");
54 sendDumpRequest(RTM_GETLINK);
55 m_isEnumeratingLinks = true;
56}
Davide Pesavento9a8bae52016-02-24 20:33:08 +010057
Junxiao Shi2dc416d2017-07-03 04:46:16 +000058NetworkMonitorImplRtnl::~NetworkMonitorImplRtnl()
Davide Pesavento2bf35a62017-04-02 00:41:06 -040059{
60 boost::system::error_code error;
61 m_socket->close(error);
62}
63
Junxiao Shi2dc416d2017-07-03 04:46:16 +000064shared_ptr<const NetworkInterface>
65NetworkMonitorImplRtnl::getNetworkInterface(const std::string& ifname) const
Davide Pesavento2bf35a62017-04-02 00:41:06 -040066{
67 for (const auto& e : m_interfaces) {
68 if (e.second->getName() == ifname)
69 return e.second;
Davide Pesavento9a8bae52016-02-24 20:33:08 +010070 }
Davide Pesavento2bf35a62017-04-02 00:41:06 -040071 return nullptr;
72}
Davide Pesavento9a8bae52016-02-24 20:33:08 +010073
Junxiao Shi2dc416d2017-07-03 04:46:16 +000074std::vector<shared_ptr<const NetworkInterface>>
75NetworkMonitorImplRtnl::listNetworkInterfaces() const
Davide Pesavento2bf35a62017-04-02 00:41:06 -040076{
Junxiao Shi2dc416d2017-07-03 04:46:16 +000077 std::vector<shared_ptr<const NetworkInterface>> v;
Davide Pesavento2bf35a62017-04-02 00:41:06 -040078 v.reserve(m_interfaces.size());
Davide Pesavento9a8bae52016-02-24 20:33:08 +010079
Davide Pesavento2bf35a62017-04-02 00:41:06 -040080 for (const auto& e : m_interfaces) {
81 v.push_back(e.second);
82 }
83 return v;
84}
85
86bool
Junxiao Shi2dc416d2017-07-03 04:46:16 +000087NetworkMonitorImplRtnl::isEnumerating() const
Davide Pesavento2bf35a62017-04-02 00:41:06 -040088{
89 return m_isEnumeratingLinks || m_isEnumeratingAddresses;
Davide Pesavento9a8bae52016-02-24 20:33:08 +010090}
91
92void
Junxiao Shi2dc416d2017-07-03 04:46:16 +000093NetworkMonitorImplRtnl::initSocket()
Davide Pesavento9a8bae52016-02-24 20:33:08 +010094{
Davide Pesavento2bf35a62017-04-02 00:41:06 -040095 NDN_LOG_TRACE("creating netlink socket");
96
97 int fd = ::socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
98 if (fd < 0) {
99 BOOST_THROW_EXCEPTION(Error(std::string("Cannot create netlink socket (") +
100 std::strerror(errno) + ")"));
101 }
102 m_socket->assign(fd);
103
104 sockaddr_nl addr{};
105 addr.nl_family = AF_NETLINK;
106 addr.nl_groups = RTMGRP_LINK | RTMGRP_NOTIFY |
107 RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
108 RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
109 if (::bind(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
110 BOOST_THROW_EXCEPTION(Error(std::string("Cannot bind netlink socket (") +
111 std::strerror(errno) + ")"));
112 }
113
114 // find out what pid has been assigned to us
115 socklen_t len = sizeof(addr);
116 if (::getsockname(fd, reinterpret_cast<sockaddr*>(&addr), &len) < 0) {
117 BOOST_THROW_EXCEPTION(Error(std::string("Cannot obtain netlink socket address (") +
118 std::strerror(errno) + ")"));
119 }
120 if (len != sizeof(addr)) {
121 BOOST_THROW_EXCEPTION(Error("Wrong address length (" + to_string(len) + ")"));
122 }
123 if (addr.nl_family != AF_NETLINK) {
124 BOOST_THROW_EXCEPTION(Error("Wrong address family (" + to_string(addr.nl_family) + ")"));
125 }
126 m_pid = addr.nl_pid;
127 NDN_LOG_TRACE("our pid is " << m_pid);
128}
129
130void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000131NetworkMonitorImplRtnl::sendDumpRequest(uint16_t nlmsgType)
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400132{
133 auto request = make_shared<RtnlRequest>();
134 request->nlh.nlmsg_len = sizeof(RtnlRequest);
135 request->nlh.nlmsg_type = nlmsgType;
136 request->nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
137 request->nlh.nlmsg_seq = ++m_sequenceNo;
138 request->nlh.nlmsg_pid = m_pid;
139 request->ifi.ifi_family = AF_UNSPEC;
140 request->rta.rta_type = IFLA_EXT_MASK;
141 request->rta.rta_len = RTA_LENGTH(sizeof(request->rtext));
142 request->rtext = 1 << 3; // RTEXT_FILTER_SKIP_STATS
143
144 boost::asio::async_write(*m_socket, boost::asio::buffer(request.get(), sizeof(RtnlRequest)),
145 // capture 'request' to prevent its premature deallocation
146 [request] (const boost::system::error_code& error, size_t) {
147 if (error && error != boost::asio::error::operation_aborted) {
148 NDN_LOG_ERROR("write failed: " << error.message());
149 BOOST_THROW_EXCEPTION(Error("Failed to send netlink request (" + error.message() + ")"));
150 }
151 });
152}
153
154static const char*
155nlmsgTypeToString(uint16_t type)
156{
Davide Pesavento88a0d812017-08-19 21:31:42 -0400157#define NLMSG_STRINGIFY(x) case NLMSG_##x: return "<" #x ">"
158#define RTM_STRINGIFY(x) case RTM_##x: return "<" #x ">"
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400159 switch (type) {
Davide Pesavento88a0d812017-08-19 21:31:42 -0400160 NLMSG_STRINGIFY(NOOP);
161 NLMSG_STRINGIFY(ERROR);
162 NLMSG_STRINGIFY(DONE);
163 NLMSG_STRINGIFY(OVERRUN);
164 RTM_STRINGIFY(NEWLINK);
165 RTM_STRINGIFY(DELLINK);
166 RTM_STRINGIFY(NEWADDR);
167 RTM_STRINGIFY(DELADDR);
168 RTM_STRINGIFY(NEWROUTE);
169 RTM_STRINGIFY(DELROUTE);
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400170 default:
171 return "";
172 }
Davide Pesavento88a0d812017-08-19 21:31:42 -0400173#undef NLMSG_STRINGIFY
174#undef RTM_STRINGIFY
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400175}
176
177static InterfaceType
178ifiTypeToInterfaceType(uint16_t type)
179{
180 switch (type) {
181 case ARPHRD_ETHER:
182 return InterfaceType::ETHERNET;
183 case ARPHRD_LOOPBACK:
184 return InterfaceType::LOOPBACK;
185 default:
186 return InterfaceType::UNKNOWN;
187 }
188}
189
190static AddressFamily
191ifaFamilyToAddressFamily(uint8_t family)
192{
193 switch (family) {
194 case AF_INET:
195 return AddressFamily::V4;
196 case AF_INET6:
197 return AddressFamily::V6;
198 default:
199 return AddressFamily::UNSPECIFIED;
200 }
201}
202
203static AddressScope
204ifaScopeToAddressScope(uint8_t scope)
205{
206 switch (scope) {
207 case RT_SCOPE_NOWHERE:
208 return AddressScope::NOWHERE;
209 case RT_SCOPE_HOST:
210 return AddressScope::HOST;
211 case RT_SCOPE_LINK:
212 return AddressScope::LINK;
213 default:
214 return AddressScope::GLOBAL;
215 }
216}
217
218void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000219NetworkMonitorImplRtnl::asyncRead()
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400220{
221 m_socket->async_read_some(boost::asio::buffer(m_buffer),
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000222 bind(&NetworkMonitorImplRtnl::handleRead, this, _1, _2, m_socket));
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400223}
224
225void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000226NetworkMonitorImplRtnl::handleRead(const boost::system::error_code& error, size_t nBytesRead,
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400227 const shared_ptr<boost::asio::posix::stream_descriptor>& socket)
228{
229 if (!socket->is_open() ||
230 error == boost::asio::error::operation_aborted) {
231 // socket was closed, ignore the error
232 NDN_LOG_TRACE("socket closed or operation aborted");
233 return;
234 }
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100235 if (error) {
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400236 NDN_LOG_ERROR("read failed: " << error.message());
237 BOOST_THROW_EXCEPTION(Error("Netlink socket read failed (" + error.message() + ")"));
238 }
239
240 NDN_LOG_TRACE("read " << nBytesRead << " bytes from netlink socket");
241
242 const nlmsghdr* nlh = reinterpret_cast<const nlmsghdr*>(m_buffer.data());
243 if (!isEnumerating() || (nlh->nlmsg_seq == m_sequenceNo && nlh->nlmsg_pid == m_pid)) {
244 parseNetlinkMessage(nlh, nBytesRead);
245 }
246 else {
247 NDN_LOG_TRACE("seq/pid mismatch, ignoring");
248 }
249
250 asyncRead();
251}
252
253void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000254NetworkMonitorImplRtnl::parseNetlinkMessage(const nlmsghdr* nlh, size_t len)
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400255{
256 while (NLMSG_OK(nlh, len)) {
257 NDN_LOG_TRACE("parsing " << (nlh->nlmsg_flags & NLM_F_MULTI ? "multi-part " : "") <<
258 "message type=" << nlh->nlmsg_type << nlmsgTypeToString(nlh->nlmsg_type) <<
259 " len=" << nlh->nlmsg_len <<
260 " seq=" << nlh->nlmsg_seq <<
261 " pid=" << nlh->nlmsg_pid);
262
263 if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) {
264 NDN_LOG_ERROR("netlink dump was interrupted");
265 // TODO: technically we should retry the dump...
266 break;
267 }
268
269 if (nlh->nlmsg_type == NLMSG_DONE)
270 break;
271
272 switch (nlh->nlmsg_type) {
273 case RTM_NEWLINK:
274 case RTM_DELLINK:
275 parseLinkMessage(nlh, reinterpret_cast<const ifinfomsg*>(NLMSG_DATA(nlh)));
276 if (!isEnumerating())
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000277 this->emitSignal(onNetworkStateChanged); // backward compat
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400278 break;
279
280 case RTM_NEWADDR:
281 case RTM_DELADDR:
282 parseAddressMessage(nlh, reinterpret_cast<const ifaddrmsg*>(NLMSG_DATA(nlh)));
283 if (!isEnumerating())
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000284 this->emitSignal(onNetworkStateChanged); // backward compat
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400285 break;
286
287 case RTM_NEWROUTE:
288 case RTM_DELROUTE:
289 parseRouteMessage(nlh, reinterpret_cast<const rtmsg*>(NLMSG_DATA(nlh)));
290 if (!isEnumerating())
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000291 this->emitSignal(onNetworkStateChanged); // backward compat
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400292 break;
293
294 case NLMSG_ERROR: {
295 const nlmsgerr* err = reinterpret_cast<const nlmsgerr*>(NLMSG_DATA(nlh));
296 if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(nlmsgerr)))
297 NDN_LOG_ERROR("truncated NLMSG_ERROR");
298 else if (err->error == 0)
299 // an error code of zero indicates an ACK message, not an error
300 NDN_LOG_TRACE("ACK");
301 else
302 NDN_LOG_ERROR("NLMSG_ERROR: " << std::strerror(std::abs(err->error)));
303 break;
304 }
305 }
306
307 nlh = NLMSG_NEXT(nlh, len);
308 }
309
310 if (nlh->nlmsg_type == NLMSG_DONE && m_isEnumeratingLinks) {
311 // links enumeration complete, now request all the addresses
312 m_isEnumeratingLinks = false;
313 NDN_LOG_TRACE("enumerating addresses");
314 sendDumpRequest(RTM_GETADDR);
315 m_isEnumeratingAddresses = true;
316 }
317 else if (nlh->nlmsg_type == NLMSG_DONE && m_isEnumeratingAddresses) {
318 // links and addresses enumeration complete
319 m_isEnumeratingAddresses = false;
320 // TODO: enumerate routes
321 NDN_LOG_DEBUG("enumeration complete");
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000322 this->emitSignal(onEnumerationCompleted);
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400323 }
324}
325
326void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000327NetworkMonitorImplRtnl::parseLinkMessage(const nlmsghdr* nlh, const ifinfomsg* ifi)
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400328{
329 if (ifiTypeToInterfaceType(ifi->ifi_type) == InterfaceType::UNKNOWN) {
330 NDN_LOG_DEBUG("unhandled interface type " << ifi->ifi_type);
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100331 return;
332 }
333
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400334 shared_ptr<NetworkInterface> interface;
335 auto it = m_interfaces.find(ifi->ifi_index);
336 if (it != m_interfaces.end()) {
337 interface = it->second;
338 BOOST_ASSERT(interface != nullptr);
339 BOOST_ASSERT(interface->getIndex() == ifi->ifi_index);
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100340 }
341
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400342 if (nlh->nlmsg_type == RTM_DELLINK) {
343 if (interface != nullptr) {
344 NDN_LOG_DEBUG("removing interface " << interface->getName());
345 m_interfaces.erase(it);
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000346 this->emitSignal(onInterfaceRemoved, interface);
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400347 }
348 return;
349 }
350
351 if (interface == nullptr) {
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000352 interface = makeNetworkInterface();
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400353 interface->setIndex(ifi->ifi_index);
354 }
355 interface->setType(ifiTypeToInterfaceType(ifi->ifi_type));
356 interface->setFlags(ifi->ifi_flags);
357
358 const rtattr* rta = reinterpret_cast<const rtattr*>(IFLA_RTA(ifi));
359 size_t rtaTotalLen = IFLA_PAYLOAD(nlh);
360 uint8_t operState = linux_if::OPER_STATE_UNKNOWN;
361
362 while (RTA_OK(rta, rtaTotalLen)) {
363 size_t attrLen = RTA_PAYLOAD(rta);
364
365 switch (rta->rta_type) {
366 case IFLA_ADDRESS:
367 if (attrLen == ethernet::ADDR_LEN) {
368 ethernet::Address addr(reinterpret_cast<const uint8_t*>(RTA_DATA(rta)));
369 interface->setEthernetAddress(addr);
370 }
371 break;
372
373 case IFLA_BROADCAST:
374 if (attrLen == ethernet::ADDR_LEN) {
375 ethernet::Address addr(reinterpret_cast<const uint8_t*>(RTA_DATA(rta)));
376 interface->setEthernetBroadcastAddress(addr);
377 }
378 break;
379
380 case IFLA_IFNAME: {
381 auto attrData = reinterpret_cast<const char*>(RTA_DATA(rta));
382 if (::strnlen(attrData, attrLen) <= attrLen)
383 interface->setName(attrData);
384 break;
385 }
386
387 case IFLA_MTU:
388 if (attrLen == sizeof(uint32_t))
389 interface->setMtu(*(reinterpret_cast<const uint32_t*>(RTA_DATA(rta))));
390 break;
391
392 case IFLA_OPERSTATE:
393 if (attrLen == sizeof(uint8_t))
394 operState = *(reinterpret_cast<const uint8_t*>RTA_DATA(rta));
395 break;
396 }
397
398 rta = RTA_NEXT(rta, rtaTotalLen);
399 }
400
401 updateInterfaceState(*interface, operState);
402
403 if (it == m_interfaces.end()) {
404 NDN_LOG_DEBUG("adding interface " << interface->getName());
405 m_interfaces[interface->getIndex()] = interface;
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000406 this->emitSignal(onInterfaceAdded, interface);
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400407 }
408}
409
410void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000411NetworkMonitorImplRtnl::parseAddressMessage(const nlmsghdr* nlh, const ifaddrmsg* ifa)
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400412{
413 auto it = m_interfaces.find(ifa->ifa_index);
414 if (it == m_interfaces.end()) {
415 // unknown interface, ignore message
416 NDN_LOG_TRACE("unknown interface index " << ifa->ifa_index);
417 return;
418 }
419 auto interface = it->second;
420 BOOST_ASSERT(interface != nullptr);
421
422 namespace ip = boost::asio::ip;
Davide Pesavento25203712017-10-09 23:50:03 -0400423 ip::address ipAddr, broadcastAddr;
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000424 uint32_t flags = ifa->ifa_flags; // will be overridden by IFA_FLAGS if the attribute is present
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400425
426 const rtattr* rta = reinterpret_cast<const rtattr*>(IFA_RTA(ifa));
427 size_t rtaTotalLen = IFA_PAYLOAD(nlh);
428
429 while (RTA_OK(rta, rtaTotalLen)) {
430 auto attrData = reinterpret_cast<const unsigned char*>(RTA_DATA(rta));
431 size_t attrLen = RTA_PAYLOAD(rta);
432
433 switch (rta->rta_type) {
434 case IFA_LOCAL:
435 if (ifa->ifa_family == AF_INET && attrLen == sizeof(ip::address_v4::bytes_type)) {
436 ip::address_v4::bytes_type bytes;
437 std::copy_n(attrData, bytes.size(), bytes.begin());
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000438 ipAddr = ip::address_v4(bytes);
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400439 }
440 break;
441
442 case IFA_ADDRESS:
443 if (ifa->ifa_family == AF_INET6 && attrLen == sizeof(ip::address_v6::bytes_type)) {
444 ip::address_v6::bytes_type bytes;
445 std::copy_n(attrData, bytes.size(), bytes.begin());
Davide Pesavento25203712017-10-09 23:50:03 -0400446 ip::address_v6 v6Addr(bytes);
447 if (v6Addr.is_link_local())
448 v6Addr.scope_id(ifa->ifa_index);
449 ipAddr = v6Addr;
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400450 }
451 break;
452
453 case IFA_BROADCAST:
454 if (ifa->ifa_family == AF_INET && attrLen == sizeof(ip::address_v4::bytes_type)) {
455 ip::address_v4::bytes_type bytes;
456 std::copy_n(attrData, bytes.size(), bytes.begin());
Davide Pesavento25203712017-10-09 23:50:03 -0400457 broadcastAddr = ip::address_v4(bytes);
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400458 }
459 break;
460
461#ifdef NDN_CXX_HAVE_IFA_FLAGS
462 case IFA_FLAGS:
463 if (attrLen == sizeof(uint32_t))
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000464 flags = *(reinterpret_cast<const uint32_t*>(attrData));
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400465 break;
466#endif // NDN_CXX_HAVE_IFA_FLAGS
467 }
468
469 rta = RTA_NEXT(rta, rtaTotalLen);
470 }
471
Davide Pesavento25203712017-10-09 23:50:03 -0400472 NetworkAddress address(ifaFamilyToAddressFamily(ifa->ifa_family),
473 ipAddr,
474 broadcastAddr,
475 ifa->ifa_prefixlen,
476 ifaScopeToAddressScope(ifa->ifa_scope),
477 flags);
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000478 BOOST_ASSERT(address.getFamily() != AddressFamily::UNSPECIFIED);
479
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400480 if (nlh->nlmsg_type == RTM_NEWADDR)
481 interface->addNetworkAddress(address);
482 else if (nlh->nlmsg_type == RTM_DELADDR)
483 interface->removeNetworkAddress(address);
484}
485
486void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000487NetworkMonitorImplRtnl::parseRouteMessage(const nlmsghdr* nlh, const rtmsg* rtm)
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400488{
489 // TODO
490}
491
492void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000493NetworkMonitorImplRtnl::updateInterfaceState(NetworkInterface& interface, uint8_t operState)
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400494{
495 if (operState == linux_if::OPER_STATE_UP) {
496 interface.setState(InterfaceState::RUNNING);
497 }
498 else if (operState == linux_if::OPER_STATE_DORMANT) {
499 interface.setState(InterfaceState::DORMANT);
500 }
501 else {
502 // fallback to flags
503 auto flags = interface.getFlags();
504 if ((flags & linux_if::FLAG_LOWER_UP) && !(flags & linux_if::FLAG_DORMANT))
505 interface.setState(InterfaceState::RUNNING);
506 else if (flags & IFF_UP)
507 interface.setState(InterfaceState::NO_CARRIER);
508 else
509 interface.setState(InterfaceState::DOWN);
510 }
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100511}
512
Junxiao Shi25467942017-06-30 02:53:14 +0000513} // namespace net
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100514} // namespace ndn