blob: 3c651d61fde37d0fd2390628ac4b3bb568eb1226 [file] [log] [blame]
Davide Pesavento50b92262018-07-11 12:28:31 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2013-2018 Regents of the University of California.
4 *
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.
20 *
21 * @author Davide Pesavento <davide.pesavento@lip6.fr>
22 */
23
24#include "network-monitor-impl-netlink.hpp"
25#include "linux-if-constants.hpp"
26#include "netlink-util.hpp"
27#include "../network-address.hpp"
28#include "../network-interface.hpp"
29#include "../../util/logger.hpp"
30#include "../../util/time.hpp"
31
32#include <cerrno>
33#include <cstdlib>
34
35#include <linux/if_addr.h>
36#include <linux/if_link.h>
37#include <net/if_arp.h>
38#include <sys/socket.h>
39
40#include <boost/asio/write.hpp>
41
42#ifndef SOL_NETLINK
43#define SOL_NETLINK 270
44#endif
45
46#ifndef RTEXT_FILTER_SKIP_STATS
47#define RTEXT_FILTER_SKIP_STATS (1 << 3)
48#endif
49
50NDN_LOG_INIT(ndn.NetworkMonitor);
51
52namespace ndn {
53namespace net {
54
55struct RtnlRequest
56{
57 nlmsghdr nlh;
58 ifinfomsg ifi;
59 rtattr rta alignas(NLMSG_ALIGNTO); // rtattr has to be aligned
60 uint32_t rtext; // space for IFLA_EXT_MASK
61};
62
63NetworkMonitorImplNetlink::NetworkMonitorImplNetlink(boost::asio::io_service& io)
64 : m_socket(make_shared<boost::asio::posix::stream_descriptor>(io))
65 , m_pid(0)
66 , m_sequenceNo(static_cast<uint32_t>(time::system_clock::now().time_since_epoch().count()))
67 , m_isEnumeratingLinks(false)
68 , m_isEnumeratingAddresses(false)
69{
70 NDN_LOG_TRACE("creating NETLINK_ROUTE socket");
71 initSocket(NETLINK_ROUTE);
72 for (auto group : {RTNLGRP_LINK,
73 RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV4_ROUTE,
74 RTNLGRP_IPV6_IFADDR, RTNLGRP_IPV6_ROUTE}) {
75 joinGroup(group);
76 }
77
78 asyncRead();
79
80 NDN_LOG_TRACE("enumerating links");
81 sendDumpRequest(RTM_GETLINK);
82 m_isEnumeratingLinks = true;
83}
84
85NetworkMonitorImplNetlink::~NetworkMonitorImplNetlink()
86{
87 boost::system::error_code error;
88 m_socket->close(error);
89}
90
91shared_ptr<const NetworkInterface>
92NetworkMonitorImplNetlink::getNetworkInterface(const std::string& ifname) const
93{
94 for (const auto& e : m_interfaces) {
95 if (e.second->getName() == ifname)
96 return e.second;
97 }
98 return nullptr;
99}
100
101std::vector<shared_ptr<const NetworkInterface>>
102NetworkMonitorImplNetlink::listNetworkInterfaces() const
103{
104 std::vector<shared_ptr<const NetworkInterface>> v;
105 v.reserve(m_interfaces.size());
106
107 for (const auto& e : m_interfaces) {
108 v.push_back(e.second);
109 }
110 return v;
111}
112
113bool
114NetworkMonitorImplNetlink::isEnumerating() const
115{
116 return m_isEnumeratingLinks || m_isEnumeratingAddresses;
117}
118
119void
120NetworkMonitorImplNetlink::initSocket(int family)
121{
122 int fd = ::socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, family);
123 if (fd < 0) {
124 BOOST_THROW_EXCEPTION(Error("Cannot create netlink socket ("s + std::strerror(errno) + ")"));
125 }
126 m_socket->assign(fd);
127
128 // increase socket receive buffer to 1MB to avoid losing messages
129 const int bufsize = 1 * 1024 * 1024;
130 if (::setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize)) < 0) {
131 // not a fatal error
132 NDN_LOG_DEBUG("setting SO_RCVBUF failed: " << std::strerror(errno));
133 }
134
Davide Pesavento2aec97a2018-07-12 23:59:00 -0400135 // enable control messages for received packets to get the destination group
136 const int one = 1;
137 if (::setsockopt(fd, SOL_NETLINK, NETLINK_PKTINFO, &one, sizeof(one)) < 0) {
138 BOOST_THROW_EXCEPTION(Error("Cannot enable NETLINK_PKTINFO ("s + std::strerror(errno) + ")"));
139 }
140
Davide Pesavento50b92262018-07-11 12:28:31 -0400141 sockaddr_nl addr{};
142 addr.nl_family = AF_NETLINK;
143 if (::bind(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
144 BOOST_THROW_EXCEPTION(Error("Cannot bind netlink socket ("s + std::strerror(errno) + ")"));
145 }
146
147 // find out what pid has been assigned to us
148 socklen_t len = sizeof(addr);
149 if (::getsockname(fd, reinterpret_cast<sockaddr*>(&addr), &len) < 0) {
150 BOOST_THROW_EXCEPTION(Error("Cannot obtain netlink socket address ("s + std::strerror(errno) + ")"));
151 }
152 if (len != sizeof(addr)) {
153 BOOST_THROW_EXCEPTION(Error("Wrong address length (" + to_string(len) + ")"));
154 }
155 if (addr.nl_family != AF_NETLINK) {
156 BOOST_THROW_EXCEPTION(Error("Wrong address family (" + to_string(addr.nl_family) + ")"));
157 }
158 m_pid = addr.nl_pid;
159 NDN_LOG_TRACE("our pid is " << m_pid);
160
161#ifdef NDN_CXX_HAVE_NETLINK_EXT_ACK
162 // enable extended ACK reporting
Davide Pesavento50b92262018-07-11 12:28:31 -0400163 if (::setsockopt(fd, SOL_NETLINK, NETLINK_EXT_ACK, &one, sizeof(one)) < 0) {
164 // not a fatal error
165 NDN_LOG_DEBUG("setting NETLINK_EXT_ACK failed: " << std::strerror(errno));
166 }
167#endif // NDN_CXX_HAVE_NETLINK_EXT_ACK
168}
169
170void
171NetworkMonitorImplNetlink::joinGroup(int group)
172{
173 if (::setsockopt(m_socket->native_handle(), SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
174 &group, sizeof(group)) < 0) {
175 BOOST_THROW_EXCEPTION(Error("Cannot join netlink group " + to_string(group) +
176 " (" + std::strerror(errno) + ")"));
177 }
178}
179
180void
181NetworkMonitorImplNetlink::sendDumpRequest(uint16_t nlmsgType)
182{
183 auto request = make_shared<RtnlRequest>();
184 request->nlh.nlmsg_len = sizeof(RtnlRequest);
185 request->nlh.nlmsg_type = nlmsgType;
186 request->nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
187 request->nlh.nlmsg_seq = ++m_sequenceNo;
188 request->nlh.nlmsg_pid = m_pid;
189 request->ifi.ifi_family = AF_UNSPEC;
190 request->rta.rta_type = IFLA_EXT_MASK;
191 request->rta.rta_len = RTA_LENGTH(sizeof(request->rtext));
192 request->rtext = RTEXT_FILTER_SKIP_STATS;
193
194 boost::asio::async_write(*m_socket, boost::asio::buffer(request.get(), sizeof(RtnlRequest)),
195 // capture 'request' to prevent its premature deallocation
196 [request] (const boost::system::error_code& error, size_t) {
197 if (!error) {
198 auto type = request->nlh.nlmsg_type;
199 NDN_LOG_TRACE("sent dump request type=" << type << nlmsgTypeToString(type)
200 << " seq=" << request->nlh.nlmsg_seq);
201 }
202 else if (error != boost::asio::error::operation_aborted) {
203 NDN_LOG_ERROR("write failed: " << error.message());
204 BOOST_THROW_EXCEPTION(Error("Failed to send netlink request (" + error.message() + ")"));
205 }
206 });
207}
208
209void
210NetworkMonitorImplNetlink::asyncRead()
211{
Davide Pesavento2aec97a2018-07-12 23:59:00 -0400212 m_socket->async_read_some(boost::asio::null_buffers(),
Davide Pesavento50b92262018-07-11 12:28:31 -0400213 // capture a copy of 'm_socket' to prevent its deallocation while the handler is still pending
Davide Pesavento2aec97a2018-07-12 23:59:00 -0400214 [this, socket = m_socket] (const auto& error, auto&&...) {
215 if (!socket->is_open() || error == boost::asio::error::operation_aborted) {
216 // socket was closed, ignore the error
217 NDN_LOG_DEBUG("socket closed or operation aborted");
218 }
219 else if (error) {
220 NDN_LOG_ERROR("read failed: " << error.message());
221 BOOST_THROW_EXCEPTION(Error("Netlink socket read error (" + error.message() + ")"));
222 }
223 else {
224 this->receiveMessage();
225 this->asyncRead();
226 }
227 });
Davide Pesavento50b92262018-07-11 12:28:31 -0400228}
229
230void
Davide Pesavento2aec97a2018-07-12 23:59:00 -0400231NetworkMonitorImplNetlink::receiveMessage()
Davide Pesavento50b92262018-07-11 12:28:31 -0400232{
Davide Pesavento2aec97a2018-07-12 23:59:00 -0400233 msghdr msg{};
234 sockaddr_nl sender{};
235 msg.msg_name = &sender;
236 msg.msg_namelen = sizeof(sender);
237 iovec iov{};
238 iov.iov_base = m_buffer.data();
239 iov.iov_len = m_buffer.size();
240 msg.msg_iov = &iov;
241 msg.msg_iovlen = 1;
242 std::array<uint8_t, CMSG_SPACE(sizeof(nl_pktinfo))> cmsgBuffer;
243 msg.msg_control = cmsgBuffer.data();
244 msg.msg_controllen = cmsgBuffer.size();
245
246 ssize_t nBytesRead = ::recvmsg(m_socket->native_handle(), &msg, 0);
247 if (nBytesRead < 0) {
248 std::string errorString = std::strerror(errno);
249 if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
250 NDN_LOG_DEBUG("recvmsg failed: " << errorString);
251 return;
252 }
253 else {
254 NDN_LOG_ERROR("recvmsg failed: " << errorString);
255 BOOST_THROW_EXCEPTION(Error("Netlink socket receive error (" + errorString + ")"));
256 }
Davide Pesavento50b92262018-07-11 12:28:31 -0400257 }
258
259 NDN_LOG_TRACE("read " << nBytesRead << " bytes from netlink socket");
260
Davide Pesavento2aec97a2018-07-12 23:59:00 -0400261 if (msg.msg_flags & MSG_TRUNC) {
262 NDN_LOG_ERROR("truncated message");
263 BOOST_THROW_EXCEPTION(Error("Received truncated netlink message"));
264 // TODO: grow the buffer and start over
265 }
266
267 if (msg.msg_namelen >= sizeof(sockaddr_nl) && sender.nl_pid != 0) {
268 NDN_LOG_TRACE("ignoring message from pid=" << sender.nl_pid);
269 return;
270 }
271
272 if (nBytesRead == 0) {
273 return;
274 }
275
276 uint32_t nlGroup = 0;
277 for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
278 if (cmsg->cmsg_level == SOL_NETLINK &&
279 cmsg->cmsg_type == NETLINK_PKTINFO &&
280 cmsg->cmsg_len == CMSG_LEN(sizeof(nl_pktinfo))) {
281 const nl_pktinfo* pktinfo = reinterpret_cast<nl_pktinfo*>(CMSG_DATA(cmsg));
282 nlGroup = pktinfo->group;
283 }
284 }
285
286 NetlinkMessage nlmsg(m_buffer.data(), static_cast<size_t>(nBytesRead));
Davide Pesavento50b92262018-07-11 12:28:31 -0400287 for (; nlmsg.isValid(); nlmsg = nlmsg.getNext()) {
288 NDN_LOG_TRACE("parsing " << (nlmsg->nlmsg_flags & NLM_F_MULTI ? "multi-part " : "") <<
289 "message type=" << nlmsg->nlmsg_type << nlmsgTypeToString(nlmsg->nlmsg_type) <<
290 " len=" << nlmsg->nlmsg_len <<
291 " seq=" << nlmsg->nlmsg_seq <<
Davide Pesavento2aec97a2018-07-12 23:59:00 -0400292 " pid=" << nlmsg->nlmsg_pid <<
293 " group=" << nlGroup);
Davide Pesavento50b92262018-07-11 12:28:31 -0400294
Davide Pesavento2aec97a2018-07-12 23:59:00 -0400295 if (nlGroup == 0 && // not a multicast notification
296 (nlmsg->nlmsg_pid != m_pid || nlmsg->nlmsg_seq != m_sequenceNo)) { // not for us
Davide Pesavento50b92262018-07-11 12:28:31 -0400297 NDN_LOG_TRACE("seq/pid mismatch, ignoring");
298 continue;
299 }
300
301 if (nlmsg->nlmsg_flags & NLM_F_DUMP_INTR) {
Davide Pesavento2aec97a2018-07-12 23:59:00 -0400302 NDN_LOG_ERROR("dump is inconsistent");
303 BOOST_THROW_EXCEPTION(Error("Inconsistency detected in netlink dump"));
Davide Pesavento50b92262018-07-11 12:28:31 -0400304 // TODO: discard the rest of the message and retry the dump
Davide Pesavento50b92262018-07-11 12:28:31 -0400305 }
306
307 if (nlmsg->nlmsg_type == NLMSG_DONE) {
308 break;
309 }
310
311 parseNetlinkMessage(nlmsg);
312 }
313
314 if (nlmsg->nlmsg_type == NLMSG_DONE) {
315 if (m_isEnumeratingLinks) {
316 // links enumeration complete, now request all the addresses
317 m_isEnumeratingLinks = false;
318 NDN_LOG_TRACE("enumerating addresses");
319 sendDumpRequest(RTM_GETADDR);
320 m_isEnumeratingAddresses = true;
321 }
322 else if (m_isEnumeratingAddresses) {
323 // links and addresses enumeration complete
324 m_isEnumeratingAddresses = false;
325 // TODO: enumerate routes
326 NDN_LOG_DEBUG("enumeration complete");
327 this->emitSignal(onEnumerationCompleted);
328 }
329 }
Davide Pesavento50b92262018-07-11 12:28:31 -0400330}
331
332void
333NetworkMonitorImplNetlink::parseNetlinkMessage(const NetlinkMessage& nlmsg)
334{
335 switch (nlmsg->nlmsg_type) {
336 case RTM_NEWLINK:
337 case RTM_DELLINK:
338 parseLinkMessage(nlmsg);
339 if (!isEnumerating())
340 this->emitSignal(onNetworkStateChanged); // backward compat
341 break;
342
343 case RTM_NEWADDR:
344 case RTM_DELADDR:
345 parseAddressMessage(nlmsg);
346 if (!isEnumerating())
347 this->emitSignal(onNetworkStateChanged); // backward compat
348 break;
349
350 case RTM_NEWROUTE:
351 case RTM_DELROUTE:
352 parseRouteMessage(nlmsg);
353 if (!isEnumerating())
354 this->emitSignal(onNetworkStateChanged); // backward compat
355 break;
356
357 case NLMSG_ERROR:
358 parseErrorMessage(nlmsg);
359 break;
360 }
361}
362
363static InterfaceType
364ifiTypeToInterfaceType(uint16_t type)
365{
366 switch (type) {
367 case ARPHRD_ETHER:
368 return InterfaceType::ETHERNET;
369 case ARPHRD_LOOPBACK:
370 return InterfaceType::LOOPBACK;
371 default:
372 return InterfaceType::UNKNOWN;
373 }
374}
375
376static AddressFamily
377ifaFamilyToAddressFamily(uint8_t family)
378{
379 switch (family) {
380 case AF_INET:
381 return AddressFamily::V4;
382 case AF_INET6:
383 return AddressFamily::V6;
384 default:
385 return AddressFamily::UNSPECIFIED;
386 }
387}
388
389static AddressScope
390ifaScopeToAddressScope(uint8_t scope)
391{
392 switch (scope) {
393 case RT_SCOPE_NOWHERE:
394 return AddressScope::NOWHERE;
395 case RT_SCOPE_HOST:
396 return AddressScope::HOST;
397 case RT_SCOPE_LINK:
398 return AddressScope::LINK;
399 default:
400 return AddressScope::GLOBAL;
401 }
402}
403
404void
405NetworkMonitorImplNetlink::parseLinkMessage(const NetlinkMessage& nlmsg)
406{
407 const ifinfomsg* ifi = nlmsg.getPayload<ifinfomsg>();
408 if (ifi == nullptr) {
409 NDN_LOG_WARN("malformed ifinfomsg");
410 return;
411 }
412
413 if (ifiTypeToInterfaceType(ifi->ifi_type) == InterfaceType::UNKNOWN) {
414 NDN_LOG_DEBUG("unhandled interface type " << ifi->ifi_type);
415 return;
416 }
417
418 shared_ptr<NetworkInterface> interface;
419 auto it = m_interfaces.find(ifi->ifi_index);
420 if (it != m_interfaces.end()) {
421 interface = it->second;
422 BOOST_ASSERT(interface != nullptr);
423 BOOST_ASSERT(interface->getIndex() == ifi->ifi_index);
424 }
425
426 if (nlmsg->nlmsg_type == RTM_DELLINK) {
427 if (interface != nullptr) {
428 NDN_LOG_DEBUG("removing interface " << interface->getName());
429 m_interfaces.erase(it);
430 this->emitSignal(onInterfaceRemoved, interface);
431 }
432 return;
433 }
434
435 if (interface == nullptr) {
436 interface = makeNetworkInterface();
437 interface->setIndex(ifi->ifi_index);
438 }
439 interface->setType(ifiTypeToInterfaceType(ifi->ifi_type));
440 interface->setFlags(ifi->ifi_flags);
441
442 auto attrs = nlmsg.getAttributes<rtattr>(ifi);
443 NDN_LOG_TRACE("message contains " << attrs.size() << " attributes");
444
445 auto address = attrs.getAttributeByType<ethernet::Address>(IFLA_ADDRESS);
446 if (address)
447 interface->setEthernetAddress(*address);
448
449 auto broadcast = attrs.getAttributeByType<ethernet::Address>(IFLA_BROADCAST);
450 if (broadcast)
451 interface->setEthernetBroadcastAddress(*broadcast);
452
453 auto name = attrs.getAttributeByType<std::string>(IFLA_IFNAME);
454 if (name)
455 interface->setName(*name);
456
457 auto mtu = attrs.getAttributeByType<uint32_t>(IFLA_MTU);
458 if (mtu)
459 interface->setMtu(*mtu);
460
461 auto state = attrs.getAttributeByType<uint8_t>(IFLA_OPERSTATE);
462 updateInterfaceState(*interface, state ? *state : linux_if::OPER_STATE_UNKNOWN);
463
464 if (it == m_interfaces.end()) {
465 NDN_LOG_DEBUG("adding interface " << interface->getName());
466 m_interfaces[interface->getIndex()] = interface;
467 this->emitSignal(onInterfaceAdded, interface);
468 }
469}
470
471void
472NetworkMonitorImplNetlink::parseAddressMessage(const NetlinkMessage& nlmsg)
473{
474 const ifaddrmsg* ifa = nlmsg.getPayload<ifaddrmsg>();
475 if (ifa == nullptr) {
476 NDN_LOG_WARN("malformed ifaddrmsg");
477 return;
478 }
479
480 auto it = m_interfaces.find(ifa->ifa_index);
481 if (it == m_interfaces.end()) {
482 // unknown interface, ignore message
483 NDN_LOG_TRACE("unknown interface index " << ifa->ifa_index);
484 return;
485 }
486 auto interface = it->second;
487 BOOST_ASSERT(interface != nullptr);
488
489 auto attrs = nlmsg.getAttributes<rtattr>(ifa);
490 NDN_LOG_TRACE("message contains " << attrs.size() << " attributes");
491
492 namespace ip = boost::asio::ip;
493 ip::address ipAddr, broadcastAddr;
494 if (ifa->ifa_family == AF_INET) {
495 auto v4 = attrs.getAttributeByType<ip::address_v4>(IFA_LOCAL);
496 if (v4)
497 ipAddr = *v4;
498
499 v4 = attrs.getAttributeByType<ip::address_v4>(IFA_BROADCAST);
500 if (v4)
501 broadcastAddr = *v4;
502 }
503 else if (ifa->ifa_family == AF_INET6) {
504 auto v6 = attrs.getAttributeByType<ip::address_v6>(IFA_ADDRESS);
505 if (v6) {
506 if (v6->is_link_local())
507 v6->scope_id(ifa->ifa_index);
508
509 ipAddr = *v6;
510 }
511 }
512
513 uint32_t flags = ifa->ifa_flags; // overwritten by IFA_FLAGS if supported and present
514#ifdef NDN_CXX_HAVE_IFA_FLAGS
515 auto extFlags = attrs.getAttributeByType<uint32_t>(IFA_FLAGS);
516 if (extFlags)
517 flags = *extFlags;
518#endif // NDN_CXX_HAVE_IFA_FLAGS
519
520 NetworkAddress address(ifaFamilyToAddressFamily(ifa->ifa_family),
521 ipAddr,
522 broadcastAddr,
523 ifa->ifa_prefixlen,
524 ifaScopeToAddressScope(ifa->ifa_scope),
525 flags);
526 BOOST_ASSERT(address.getFamily() != AddressFamily::UNSPECIFIED);
527
528 if (nlmsg->nlmsg_type == RTM_NEWADDR)
529 interface->addNetworkAddress(address);
530 else if (nlmsg->nlmsg_type == RTM_DELADDR)
531 interface->removeNetworkAddress(address);
532}
533
534void
535NetworkMonitorImplNetlink::parseRouteMessage(const NetlinkMessage& nlmsg)
536{
537 // TODO
538}
539
540void
541NetworkMonitorImplNetlink::parseErrorMessage(const NetlinkMessage& nlmsg)
542{
543 const nlmsgerr* err = nlmsg.getPayload<nlmsgerr>();
544 if (err == nullptr) {
545 NDN_LOG_WARN("malformed nlmsgerr");
546 return;
547 }
548
549 if (err->error == 0) {
550 // an error code of zero indicates an ACK message, not an error
551 NDN_LOG_TRACE("ACK");
552 return;
553 }
554
555 NDN_LOG_ERROR("NLMSG_ERROR: " << std::strerror(std::abs(err->error)));
556
557#ifdef NDN_CXX_HAVE_NETLINK_EXT_ACK
558 if (!(nlmsg->nlmsg_flags & NLM_F_ACK_TLVS))
559 return;
560
561 size_t errLen = NLMSG_LENGTH(sizeof(nlmsgerr));
562 if (!(nlmsg->nlmsg_flags & NLM_F_CAPPED))
563 errLen += err->msg.nlmsg_len - NLMSG_HDRLEN; // don't count the inner nlmsghdr twice
564
565 if (nlmsg->nlmsg_len <= errLen)
566 return;
567
568 auto nla = reinterpret_cast<const nlattr*>(reinterpret_cast<const uint8_t*>(&*nlmsg) + errLen);
569 auto attrs = NetlinkMessageAttributes<nlattr>(nla, nlmsg->nlmsg_len - errLen);
570 auto msg = attrs.getAttributeByType<std::string>(NLMSGERR_ATTR_MSG);
571 if (msg)
572 NDN_LOG_ERROR("kernel message: " << *msg);
573#endif // NDN_CXX_HAVE_NETLINK_EXT_ACK
574}
575
576void
577NetworkMonitorImplNetlink::updateInterfaceState(NetworkInterface& interface, uint8_t operState)
578{
579 if (operState == linux_if::OPER_STATE_UP) {
580 interface.setState(InterfaceState::RUNNING);
581 }
582 else if (operState == linux_if::OPER_STATE_DORMANT) {
583 interface.setState(InterfaceState::DORMANT);
584 }
585 else {
586 // fallback to flags
587 auto flags = interface.getFlags();
588 if ((flags & linux_if::FLAG_LOWER_UP) && !(flags & linux_if::FLAG_DORMANT))
589 interface.setState(InterfaceState::RUNNING);
590 else if (flags & IFF_UP)
591 interface.setState(InterfaceState::NO_CARRIER);
592 else
593 interface.setState(InterfaceState::DOWN);
594 }
595}
596
597} // namespace net
598} // namespace ndn