blob: ab797dba1175d1c71951b2fda30356481065aebf [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 Pesaventodb4da5e2018-06-15 11:37:52 -04003 * Copyright (c) 2013-2018 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) {
Davide Pesaventodb4da5e2018-06-15 11:37:52 -040099 BOOST_THROW_EXCEPTION(Error("Cannot create netlink socket ("s + std::strerror(errno) + ")"));
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400100 }
101 m_socket->assign(fd);
102
103 sockaddr_nl addr{};
104 addr.nl_family = AF_NETLINK;
105 addr.nl_groups = RTMGRP_LINK | RTMGRP_NOTIFY |
106 RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
107 RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
108 if (::bind(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400109 BOOST_THROW_EXCEPTION(Error("Cannot bind netlink socket ("s + std::strerror(errno) + ")"));
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400110 }
111
112 // find out what pid has been assigned to us
113 socklen_t len = sizeof(addr);
114 if (::getsockname(fd, reinterpret_cast<sockaddr*>(&addr), &len) < 0) {
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400115 BOOST_THROW_EXCEPTION(Error("Cannot obtain netlink socket address ("s + std::strerror(errno) + ")"));
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400116 }
117 if (len != sizeof(addr)) {
118 BOOST_THROW_EXCEPTION(Error("Wrong address length (" + to_string(len) + ")"));
119 }
120 if (addr.nl_family != AF_NETLINK) {
121 BOOST_THROW_EXCEPTION(Error("Wrong address family (" + to_string(addr.nl_family) + ")"));
122 }
123 m_pid = addr.nl_pid;
124 NDN_LOG_TRACE("our pid is " << m_pid);
125}
126
127void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000128NetworkMonitorImplRtnl::sendDumpRequest(uint16_t nlmsgType)
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400129{
130 auto request = make_shared<RtnlRequest>();
131 request->nlh.nlmsg_len = sizeof(RtnlRequest);
132 request->nlh.nlmsg_type = nlmsgType;
133 request->nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
134 request->nlh.nlmsg_seq = ++m_sequenceNo;
135 request->nlh.nlmsg_pid = m_pid;
136 request->ifi.ifi_family = AF_UNSPEC;
137 request->rta.rta_type = IFLA_EXT_MASK;
138 request->rta.rta_len = RTA_LENGTH(sizeof(request->rtext));
139 request->rtext = 1 << 3; // RTEXT_FILTER_SKIP_STATS
140
141 boost::asio::async_write(*m_socket, boost::asio::buffer(request.get(), sizeof(RtnlRequest)),
142 // capture 'request' to prevent its premature deallocation
143 [request] (const boost::system::error_code& error, size_t) {
144 if (error && error != boost::asio::error::operation_aborted) {
145 NDN_LOG_ERROR("write failed: " << error.message());
146 BOOST_THROW_EXCEPTION(Error("Failed to send netlink request (" + error.message() + ")"));
147 }
148 });
149}
150
151static const char*
152nlmsgTypeToString(uint16_t type)
153{
Davide Pesavento88a0d812017-08-19 21:31:42 -0400154#define NLMSG_STRINGIFY(x) case NLMSG_##x: return "<" #x ">"
155#define RTM_STRINGIFY(x) case RTM_##x: return "<" #x ">"
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400156 switch (type) {
Davide Pesavento88a0d812017-08-19 21:31:42 -0400157 NLMSG_STRINGIFY(NOOP);
158 NLMSG_STRINGIFY(ERROR);
159 NLMSG_STRINGIFY(DONE);
160 NLMSG_STRINGIFY(OVERRUN);
161 RTM_STRINGIFY(NEWLINK);
162 RTM_STRINGIFY(DELLINK);
163 RTM_STRINGIFY(NEWADDR);
164 RTM_STRINGIFY(DELADDR);
165 RTM_STRINGIFY(NEWROUTE);
166 RTM_STRINGIFY(DELROUTE);
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400167 default:
168 return "";
169 }
Davide Pesavento88a0d812017-08-19 21:31:42 -0400170#undef NLMSG_STRINGIFY
171#undef RTM_STRINGIFY
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400172}
173
174static InterfaceType
175ifiTypeToInterfaceType(uint16_t type)
176{
177 switch (type) {
178 case ARPHRD_ETHER:
179 return InterfaceType::ETHERNET;
180 case ARPHRD_LOOPBACK:
181 return InterfaceType::LOOPBACK;
182 default:
183 return InterfaceType::UNKNOWN;
184 }
185}
186
187static AddressFamily
188ifaFamilyToAddressFamily(uint8_t family)
189{
190 switch (family) {
191 case AF_INET:
192 return AddressFamily::V4;
193 case AF_INET6:
194 return AddressFamily::V6;
195 default:
196 return AddressFamily::UNSPECIFIED;
197 }
198}
199
200static AddressScope
201ifaScopeToAddressScope(uint8_t scope)
202{
203 switch (scope) {
204 case RT_SCOPE_NOWHERE:
205 return AddressScope::NOWHERE;
206 case RT_SCOPE_HOST:
207 return AddressScope::HOST;
208 case RT_SCOPE_LINK:
209 return AddressScope::LINK;
210 default:
211 return AddressScope::GLOBAL;
212 }
213}
214
215void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000216NetworkMonitorImplRtnl::asyncRead()
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400217{
218 m_socket->async_read_some(boost::asio::buffer(m_buffer),
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000219 bind(&NetworkMonitorImplRtnl::handleRead, this, _1, _2, m_socket));
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400220}
221
222void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000223NetworkMonitorImplRtnl::handleRead(const boost::system::error_code& error, size_t nBytesRead,
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400224 const shared_ptr<boost::asio::posix::stream_descriptor>& socket)
225{
226 if (!socket->is_open() ||
227 error == boost::asio::error::operation_aborted) {
228 // socket was closed, ignore the error
229 NDN_LOG_TRACE("socket closed or operation aborted");
230 return;
231 }
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100232 if (error) {
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400233 NDN_LOG_ERROR("read failed: " << error.message());
234 BOOST_THROW_EXCEPTION(Error("Netlink socket read failed (" + error.message() + ")"));
235 }
236
237 NDN_LOG_TRACE("read " << nBytesRead << " bytes from netlink socket");
238
239 const nlmsghdr* nlh = reinterpret_cast<const nlmsghdr*>(m_buffer.data());
240 if (!isEnumerating() || (nlh->nlmsg_seq == m_sequenceNo && nlh->nlmsg_pid == m_pid)) {
241 parseNetlinkMessage(nlh, nBytesRead);
242 }
243 else {
244 NDN_LOG_TRACE("seq/pid mismatch, ignoring");
245 }
246
247 asyncRead();
248}
249
250void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000251NetworkMonitorImplRtnl::parseNetlinkMessage(const nlmsghdr* nlh, size_t len)
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400252{
253 while (NLMSG_OK(nlh, len)) {
254 NDN_LOG_TRACE("parsing " << (nlh->nlmsg_flags & NLM_F_MULTI ? "multi-part " : "") <<
255 "message type=" << nlh->nlmsg_type << nlmsgTypeToString(nlh->nlmsg_type) <<
256 " len=" << nlh->nlmsg_len <<
257 " seq=" << nlh->nlmsg_seq <<
258 " pid=" << nlh->nlmsg_pid);
259
260 if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) {
261 NDN_LOG_ERROR("netlink dump was interrupted");
262 // TODO: technically we should retry the dump...
263 break;
264 }
265
266 if (nlh->nlmsg_type == NLMSG_DONE)
267 break;
268
269 switch (nlh->nlmsg_type) {
270 case RTM_NEWLINK:
271 case RTM_DELLINK:
272 parseLinkMessage(nlh, reinterpret_cast<const ifinfomsg*>(NLMSG_DATA(nlh)));
273 if (!isEnumerating())
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000274 this->emitSignal(onNetworkStateChanged); // backward compat
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400275 break;
276
277 case RTM_NEWADDR:
278 case RTM_DELADDR:
279 parseAddressMessage(nlh, reinterpret_cast<const ifaddrmsg*>(NLMSG_DATA(nlh)));
280 if (!isEnumerating())
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000281 this->emitSignal(onNetworkStateChanged); // backward compat
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400282 break;
283
284 case RTM_NEWROUTE:
285 case RTM_DELROUTE:
286 parseRouteMessage(nlh, reinterpret_cast<const rtmsg*>(NLMSG_DATA(nlh)));
287 if (!isEnumerating())
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000288 this->emitSignal(onNetworkStateChanged); // backward compat
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400289 break;
290
291 case NLMSG_ERROR: {
292 const nlmsgerr* err = reinterpret_cast<const nlmsgerr*>(NLMSG_DATA(nlh));
293 if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(nlmsgerr)))
294 NDN_LOG_ERROR("truncated NLMSG_ERROR");
295 else if (err->error == 0)
296 // an error code of zero indicates an ACK message, not an error
297 NDN_LOG_TRACE("ACK");
298 else
299 NDN_LOG_ERROR("NLMSG_ERROR: " << std::strerror(std::abs(err->error)));
300 break;
301 }
302 }
303
304 nlh = NLMSG_NEXT(nlh, len);
305 }
306
307 if (nlh->nlmsg_type == NLMSG_DONE && m_isEnumeratingLinks) {
308 // links enumeration complete, now request all the addresses
309 m_isEnumeratingLinks = false;
310 NDN_LOG_TRACE("enumerating addresses");
311 sendDumpRequest(RTM_GETADDR);
312 m_isEnumeratingAddresses = true;
313 }
314 else if (nlh->nlmsg_type == NLMSG_DONE && m_isEnumeratingAddresses) {
315 // links and addresses enumeration complete
316 m_isEnumeratingAddresses = false;
317 // TODO: enumerate routes
318 NDN_LOG_DEBUG("enumeration complete");
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000319 this->emitSignal(onEnumerationCompleted);
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400320 }
321}
322
323void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000324NetworkMonitorImplRtnl::parseLinkMessage(const nlmsghdr* nlh, const ifinfomsg* ifi)
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400325{
326 if (ifiTypeToInterfaceType(ifi->ifi_type) == InterfaceType::UNKNOWN) {
327 NDN_LOG_DEBUG("unhandled interface type " << ifi->ifi_type);
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100328 return;
329 }
330
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400331 shared_ptr<NetworkInterface> interface;
332 auto it = m_interfaces.find(ifi->ifi_index);
333 if (it != m_interfaces.end()) {
334 interface = it->second;
335 BOOST_ASSERT(interface != nullptr);
336 BOOST_ASSERT(interface->getIndex() == ifi->ifi_index);
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100337 }
338
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400339 if (nlh->nlmsg_type == RTM_DELLINK) {
340 if (interface != nullptr) {
341 NDN_LOG_DEBUG("removing interface " << interface->getName());
342 m_interfaces.erase(it);
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000343 this->emitSignal(onInterfaceRemoved, interface);
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400344 }
345 return;
346 }
347
348 if (interface == nullptr) {
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000349 interface = makeNetworkInterface();
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400350 interface->setIndex(ifi->ifi_index);
351 }
352 interface->setType(ifiTypeToInterfaceType(ifi->ifi_type));
353 interface->setFlags(ifi->ifi_flags);
354
355 const rtattr* rta = reinterpret_cast<const rtattr*>(IFLA_RTA(ifi));
356 size_t rtaTotalLen = IFLA_PAYLOAD(nlh);
357 uint8_t operState = linux_if::OPER_STATE_UNKNOWN;
358
359 while (RTA_OK(rta, rtaTotalLen)) {
360 size_t attrLen = RTA_PAYLOAD(rta);
361
362 switch (rta->rta_type) {
363 case IFLA_ADDRESS:
364 if (attrLen == ethernet::ADDR_LEN) {
365 ethernet::Address addr(reinterpret_cast<const uint8_t*>(RTA_DATA(rta)));
366 interface->setEthernetAddress(addr);
367 }
368 break;
369
370 case IFLA_BROADCAST:
371 if (attrLen == ethernet::ADDR_LEN) {
372 ethernet::Address addr(reinterpret_cast<const uint8_t*>(RTA_DATA(rta)));
373 interface->setEthernetBroadcastAddress(addr);
374 }
375 break;
376
377 case IFLA_IFNAME: {
378 auto attrData = reinterpret_cast<const char*>(RTA_DATA(rta));
379 if (::strnlen(attrData, attrLen) <= attrLen)
380 interface->setName(attrData);
381 break;
382 }
383
384 case IFLA_MTU:
385 if (attrLen == sizeof(uint32_t))
386 interface->setMtu(*(reinterpret_cast<const uint32_t*>(RTA_DATA(rta))));
387 break;
388
389 case IFLA_OPERSTATE:
390 if (attrLen == sizeof(uint8_t))
391 operState = *(reinterpret_cast<const uint8_t*>RTA_DATA(rta));
392 break;
393 }
394
395 rta = RTA_NEXT(rta, rtaTotalLen);
396 }
397
398 updateInterfaceState(*interface, operState);
399
400 if (it == m_interfaces.end()) {
401 NDN_LOG_DEBUG("adding interface " << interface->getName());
402 m_interfaces[interface->getIndex()] = interface;
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000403 this->emitSignal(onInterfaceAdded, interface);
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400404 }
405}
406
407void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000408NetworkMonitorImplRtnl::parseAddressMessage(const nlmsghdr* nlh, const ifaddrmsg* ifa)
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400409{
410 auto it = m_interfaces.find(ifa->ifa_index);
411 if (it == m_interfaces.end()) {
412 // unknown interface, ignore message
413 NDN_LOG_TRACE("unknown interface index " << ifa->ifa_index);
414 return;
415 }
416 auto interface = it->second;
417 BOOST_ASSERT(interface != nullptr);
418
419 namespace ip = boost::asio::ip;
Davide Pesavento25203712017-10-09 23:50:03 -0400420 ip::address ipAddr, broadcastAddr;
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000421 uint32_t flags = ifa->ifa_flags; // will be overridden by IFA_FLAGS if the attribute is present
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400422
423 const rtattr* rta = reinterpret_cast<const rtattr*>(IFA_RTA(ifa));
424 size_t rtaTotalLen = IFA_PAYLOAD(nlh);
425
426 while (RTA_OK(rta, rtaTotalLen)) {
427 auto attrData = reinterpret_cast<const unsigned char*>(RTA_DATA(rta));
428 size_t attrLen = RTA_PAYLOAD(rta);
429
430 switch (rta->rta_type) {
431 case IFA_LOCAL:
432 if (ifa->ifa_family == AF_INET && attrLen == sizeof(ip::address_v4::bytes_type)) {
433 ip::address_v4::bytes_type bytes;
434 std::copy_n(attrData, bytes.size(), bytes.begin());
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000435 ipAddr = ip::address_v4(bytes);
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400436 }
437 break;
438
439 case IFA_ADDRESS:
440 if (ifa->ifa_family == AF_INET6 && attrLen == sizeof(ip::address_v6::bytes_type)) {
441 ip::address_v6::bytes_type bytes;
442 std::copy_n(attrData, bytes.size(), bytes.begin());
Davide Pesavento25203712017-10-09 23:50:03 -0400443 ip::address_v6 v6Addr(bytes);
444 if (v6Addr.is_link_local())
445 v6Addr.scope_id(ifa->ifa_index);
446 ipAddr = v6Addr;
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400447 }
448 break;
449
450 case IFA_BROADCAST:
451 if (ifa->ifa_family == AF_INET && attrLen == sizeof(ip::address_v4::bytes_type)) {
452 ip::address_v4::bytes_type bytes;
453 std::copy_n(attrData, bytes.size(), bytes.begin());
Davide Pesavento25203712017-10-09 23:50:03 -0400454 broadcastAddr = ip::address_v4(bytes);
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400455 }
456 break;
457
458#ifdef NDN_CXX_HAVE_IFA_FLAGS
459 case IFA_FLAGS:
460 if (attrLen == sizeof(uint32_t))
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000461 flags = *(reinterpret_cast<const uint32_t*>(attrData));
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400462 break;
463#endif // NDN_CXX_HAVE_IFA_FLAGS
464 }
465
466 rta = RTA_NEXT(rta, rtaTotalLen);
467 }
468
Davide Pesavento25203712017-10-09 23:50:03 -0400469 NetworkAddress address(ifaFamilyToAddressFamily(ifa->ifa_family),
470 ipAddr,
471 broadcastAddr,
472 ifa->ifa_prefixlen,
473 ifaScopeToAddressScope(ifa->ifa_scope),
474 flags);
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000475 BOOST_ASSERT(address.getFamily() != AddressFamily::UNSPECIFIED);
476
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400477 if (nlh->nlmsg_type == RTM_NEWADDR)
478 interface->addNetworkAddress(address);
479 else if (nlh->nlmsg_type == RTM_DELADDR)
480 interface->removeNetworkAddress(address);
481}
482
483void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000484NetworkMonitorImplRtnl::parseRouteMessage(const nlmsghdr* nlh, const rtmsg* rtm)
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400485{
486 // TODO
487}
488
489void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000490NetworkMonitorImplRtnl::updateInterfaceState(NetworkInterface& interface, uint8_t operState)
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400491{
492 if (operState == linux_if::OPER_STATE_UP) {
493 interface.setState(InterfaceState::RUNNING);
494 }
495 else if (operState == linux_if::OPER_STATE_DORMANT) {
496 interface.setState(InterfaceState::DORMANT);
497 }
498 else {
499 // fallback to flags
500 auto flags = interface.getFlags();
501 if ((flags & linux_if::FLAG_LOWER_UP) && !(flags & linux_if::FLAG_DORMANT))
502 interface.setState(InterfaceState::RUNNING);
503 else if (flags & IFF_UP)
504 interface.setState(InterfaceState::NO_CARRIER);
505 else
506 interface.setState(InterfaceState::DOWN);
507 }
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100508}
509
Junxiao Shi25467942017-06-30 02:53:14 +0000510} // namespace net
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100511} // namespace ndn