26 #include "../logger.hpp"
27 #include "../network-address.hpp"
28 #include "../network-interface.hpp"
29 #include "../time.hpp"
31 #include <boost/asio/write.hpp>
35 #include <net/if_arp.h>
36 #include <sys/socket.h>
45 , m_socket(make_shared<
boost::asio::posix::stream_descriptor>(io))
47 , m_sequenceNo(static_cast<uint32_t>(time::system_clock::now().time_since_epoch().count()))
48 , m_isEnumeratingLinks(false)
49 , m_isEnumeratingAddresses(false)
55 sendDumpRequest(RTM_GETLINK);
56 m_isEnumeratingLinks =
true;
59 NetworkMonitor::Impl::~Impl()
61 boost::system::error_code error;
62 m_socket->close(error);
65 shared_ptr<NetworkInterface>
66 NetworkMonitor::Impl::getNetworkInterface(
const std::string& ifname)
const
68 for (
const auto& e : m_interfaces) {
69 if (e.second->getName() == ifname)
75 std::vector<shared_ptr<NetworkInterface>>
76 NetworkMonitor::Impl::listNetworkInterfaces()
const
78 std::vector<shared_ptr<NetworkInterface>> v;
79 v.reserve(m_interfaces.size());
81 for (
const auto& e : m_interfaces) {
82 v.push_back(e.second);
88 NetworkMonitor::Impl::isEnumerating()
const
90 return m_isEnumeratingLinks || m_isEnumeratingAddresses;
94 NetworkMonitor::Impl::initSocket()
98 int fd = ::socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
100 BOOST_THROW_EXCEPTION(Error(std::string(
"Cannot create netlink socket (") +
101 std::strerror(errno) +
")"));
103 m_socket->assign(fd);
106 addr.nl_family = AF_NETLINK;
107 addr.nl_groups = RTMGRP_LINK | RTMGRP_NOTIFY |
108 RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
109 RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
110 if (::bind(fd, reinterpret_cast<sockaddr*>(&addr),
sizeof(addr)) < 0) {
111 BOOST_THROW_EXCEPTION(Error(std::string(
"Cannot bind netlink socket (") +
112 std::strerror(errno) +
")"));
116 socklen_t len =
sizeof(addr);
117 if (::getsockname(fd, reinterpret_cast<sockaddr*>(&addr), &len) < 0) {
118 BOOST_THROW_EXCEPTION(Error(std::string(
"Cannot obtain netlink socket address (") +
119 std::strerror(errno) +
")"));
121 if (len !=
sizeof(addr)) {
122 BOOST_THROW_EXCEPTION(Error(
"Wrong address length (" +
to_string(len) +
")"));
124 if (addr.nl_family != AF_NETLINK) {
125 BOOST_THROW_EXCEPTION(Error(
"Wrong address family (" +
to_string(addr.nl_family) +
")"));
132 NetworkMonitor::Impl::sendDumpRequest(uint16_t nlmsgType)
134 auto request = make_shared<RtnlRequest>();
135 request->nlh.nlmsg_len =
sizeof(RtnlRequest);
136 request->nlh.nlmsg_type = nlmsgType;
137 request->nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
138 request->nlh.nlmsg_seq = ++m_sequenceNo;
139 request->nlh.nlmsg_pid = m_pid;
140 request->ifi.ifi_family = AF_UNSPEC;
141 request->rta.rta_type = IFLA_EXT_MASK;
142 request->rta.rta_len = RTA_LENGTH(
sizeof(request->rtext));
143 request->rtext = 1 << 3;
145 boost::asio::async_write(*m_socket, boost::asio::buffer(request.get(),
sizeof(RtnlRequest)),
147 [request] (
const boost::system::error_code& error, size_t) {
148 if (error && error != boost::asio::error::operation_aborted) {
150 BOOST_THROW_EXCEPTION(Error(
"Failed to send netlink request (" + error.message() +
")"));
158 #define NDN_NLMSG_STRING(x) case NLMSG_##x: return "<" #x ">"
159 #define NDN_RTM_STRING(x) case RTM_##x: return "<" #x ">"
174 #undef NDN_NLMSG_STRING
175 #undef NDN_RTM_STRING
183 return InterfaceType::ETHERNET;
184 case ARPHRD_LOOPBACK:
185 return InterfaceType::LOOPBACK;
187 return InterfaceType::UNKNOWN;
196 return AddressFamily::V4;
198 return AddressFamily::V6;
200 return AddressFamily::UNSPECIFIED;
208 case RT_SCOPE_NOWHERE:
209 return AddressScope::NOWHERE;
211 return AddressScope::HOST;
213 return AddressScope::LINK;
215 return AddressScope::GLOBAL;
220 NetworkMonitor::Impl::asyncRead()
222 m_socket->async_read_some(boost::asio::buffer(m_buffer),
223 bind(&Impl::handleRead,
this, _1, _2, m_socket));
227 NetworkMonitor::Impl::handleRead(
const boost::system::error_code& error,
size_t nBytesRead,
228 const shared_ptr<boost::asio::posix::stream_descriptor>& socket)
230 if (!socket->is_open() ||
231 error == boost::asio::error::operation_aborted) {
238 BOOST_THROW_EXCEPTION(Error(
"Netlink socket read failed (" + error.message() +
")"));
241 NDN_LOG_TRACE(
"read " << nBytesRead <<
" bytes from netlink socket");
243 const nlmsghdr* nlh =
reinterpret_cast<const nlmsghdr*
>(m_buffer.data());
244 if (!isEnumerating() || (nlh->nlmsg_seq == m_sequenceNo && nlh->nlmsg_pid == m_pid)) {
245 parseNetlinkMessage(nlh, nBytesRead);
255 NetworkMonitor::Impl::parseNetlinkMessage(
const nlmsghdr* nlh,
size_t len)
257 while (NLMSG_OK(nlh, len)) {
258 NDN_LOG_TRACE(
"parsing " << (nlh->nlmsg_flags & NLM_F_MULTI ?
"multi-part " :
"") <<
260 " len=" << nlh->nlmsg_len <<
261 " seq=" << nlh->nlmsg_seq <<
262 " pid=" << nlh->nlmsg_pid);
264 if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) {
270 if (nlh->nlmsg_type == NLMSG_DONE)
273 switch (nlh->nlmsg_type) {
276 parseLinkMessage(nlh, reinterpret_cast<const ifinfomsg*>(NLMSG_DATA(nlh)));
277 if (!isEnumerating())
278 m_nm.onNetworkStateChanged();
283 parseAddressMessage(nlh, reinterpret_cast<const ifaddrmsg*>(NLMSG_DATA(nlh)));
284 if (!isEnumerating())
285 m_nm.onNetworkStateChanged();
290 parseRouteMessage(nlh, reinterpret_cast<const rtmsg*>(NLMSG_DATA(nlh)));
291 if (!isEnumerating())
292 m_nm.onNetworkStateChanged();
296 const nlmsgerr* err =
reinterpret_cast<const nlmsgerr*
>(NLMSG_DATA(nlh));
297 if (nlh->nlmsg_len < NLMSG_LENGTH(
sizeof(nlmsgerr)))
299 else if (err->error == 0)
308 nlh = NLMSG_NEXT(nlh, len);
311 if (nlh->nlmsg_type == NLMSG_DONE && m_isEnumeratingLinks) {
313 m_isEnumeratingLinks =
false;
315 sendDumpRequest(RTM_GETADDR);
316 m_isEnumeratingAddresses =
true;
318 else if (nlh->nlmsg_type == NLMSG_DONE && m_isEnumeratingAddresses) {
320 m_isEnumeratingAddresses =
false;
323 m_nm.onEnumerationCompleted();
328 NetworkMonitor::Impl::parseLinkMessage(
const nlmsghdr* nlh,
const ifinfomsg* ifi)
335 shared_ptr<NetworkInterface> interface;
336 auto it = m_interfaces.find(ifi->ifi_index);
337 if (it != m_interfaces.end()) {
338 interface = it->second;
339 BOOST_ASSERT(interface !=
nullptr);
340 BOOST_ASSERT(interface->getIndex() == ifi->ifi_index);
343 if (nlh->nlmsg_type == RTM_DELLINK) {
344 if (interface !=
nullptr) {
345 NDN_LOG_DEBUG(
"removing interface " << interface->getName());
346 m_interfaces.erase(it);
347 m_nm.onInterfaceRemoved(interface);
352 if (interface ==
nullptr) {
354 interface.reset(
new NetworkInterface);
355 interface->setIndex(ifi->ifi_index);
358 interface->setFlags(ifi->ifi_flags);
360 const rtattr* rta =
reinterpret_cast<const rtattr*
>(IFLA_RTA(ifi));
361 size_t rtaTotalLen = IFLA_PAYLOAD(nlh);
362 uint8_t operState = linux_if::OPER_STATE_UNKNOWN;
364 while (RTA_OK(rta, rtaTotalLen)) {
365 size_t attrLen = RTA_PAYLOAD(rta);
367 switch (rta->rta_type) {
370 ethernet::Address addr(reinterpret_cast<const uint8_t*>(RTA_DATA(rta)));
371 interface->setEthernetAddress(addr);
377 ethernet::Address addr(reinterpret_cast<const uint8_t*>(RTA_DATA(rta)));
378 interface->setEthernetBroadcastAddress(addr);
383 auto attrData =
reinterpret_cast<const char*
>(RTA_DATA(rta));
384 if (::strnlen(attrData, attrLen) <= attrLen)
385 interface->setName(attrData);
390 if (attrLen ==
sizeof(uint32_t))
391 interface->setMtu(*(reinterpret_cast<const uint32_t*>(RTA_DATA(rta))));
395 if (attrLen ==
sizeof(uint8_t))
396 operState = *(
reinterpret_cast<const uint8_t*
>RTA_DATA(rta));
400 rta = RTA_NEXT(rta, rtaTotalLen);
403 updateInterfaceState(*interface, operState);
405 if (it == m_interfaces.end()) {
407 m_interfaces[interface->getIndex()] = interface;
408 m_nm.onInterfaceAdded(interface);
413 NetworkMonitor::Impl::parseAddressMessage(
const nlmsghdr* nlh,
const ifaddrmsg* ifa)
415 auto it = m_interfaces.find(ifa->ifa_index);
416 if (it == m_interfaces.end()) {
421 auto interface = it->second;
422 BOOST_ASSERT(interface !=
nullptr);
426 NetworkAddress address;
428 BOOST_ASSERT(address.m_family != AddressFamily::UNSPECIFIED);
429 address.m_prefixLength = ifa->ifa_prefixlen;
430 address.m_flags = ifa->ifa_flags;
433 const rtattr* rta =
reinterpret_cast<const rtattr*
>(IFA_RTA(ifa));
434 size_t rtaTotalLen = IFA_PAYLOAD(nlh);
436 while (RTA_OK(rta, rtaTotalLen)) {
437 auto attrData =
reinterpret_cast<const unsigned char*
>(RTA_DATA(rta));
438 size_t attrLen = RTA_PAYLOAD(rta);
440 switch (rta->rta_type) {
442 if (ifa->ifa_family == AF_INET && attrLen ==
sizeof(ip::address_v4::bytes_type)) {
443 ip::address_v4::bytes_type bytes;
444 std::copy_n(attrData, bytes.size(), bytes.begin());
445 address.m_ip = ip::address_v4(bytes);
450 if (ifa->ifa_family == AF_INET6 && attrLen ==
sizeof(ip::address_v6::bytes_type)) {
451 ip::address_v6::bytes_type bytes;
452 std::copy_n(attrData, bytes.size(), bytes.begin());
453 address.m_ip = ip::address_v6(bytes);
458 if (ifa->ifa_family == AF_INET && attrLen ==
sizeof(ip::address_v4::bytes_type)) {
459 ip::address_v4::bytes_type bytes;
460 std::copy_n(attrData, bytes.size(), bytes.begin());
461 address.m_broadcast = ip::address_v4(bytes);
465 #ifdef NDN_CXX_HAVE_IFA_FLAGS
467 if (attrLen ==
sizeof(uint32_t))
468 address.m_flags = *(
reinterpret_cast<const uint32_t*
>(attrData));
470 #endif // NDN_CXX_HAVE_IFA_FLAGS
473 rta = RTA_NEXT(rta, rtaTotalLen);
476 if (nlh->nlmsg_type == RTM_NEWADDR)
477 interface->addNetworkAddress(address);
478 else if (nlh->nlmsg_type == RTM_DELADDR)
479 interface->removeNetworkAddress(address);
483 NetworkMonitor::Impl::parseRouteMessage(
const nlmsghdr* nlh,
const rtmsg* rtm)
489 NetworkMonitor::Impl::updateInterfaceState(NetworkInterface& interface, uint8_t operState)
491 if (operState == linux_if::OPER_STATE_UP) {
492 interface.setState(InterfaceState::RUNNING);
494 else if (operState == linux_if::OPER_STATE_DORMANT) {
495 interface.setState(InterfaceState::DORMANT);
499 auto flags = interface.getFlags();
500 if ((flags & linux_if::FLAG_LOWER_UP) && !(flags & linux_if::FLAG_DORMANT))
501 interface.setState(InterfaceState::RUNNING);
502 else if (flags & IFF_UP)
503 interface.setState(InterfaceState::NO_CARRIER);
505 interface.setState(InterfaceState::DOWN);
static InterfaceType ifiTypeToInterfaceType(uint16_t type)
Impl(NetworkMonitor &nm, boost::asio::io_service &io)
static const char * nlmsgTypeToString(uint16_t type)
Copyright (c) 2013-2016 Regents of the University of California.
const size_t ADDR_LEN
Octets in one Ethernet address.
Copyright (c) 2013-2016 Regents of the University of California.
#define NDN_LOG_DEBUG(expression)
log at DEBUG level
#define NDN_LOG_INIT(name)
declare a log module
constexpr duration< Rep, Period > abs(duration< Rep, Period > d)
ndn NetworkMonitor
Copyright (c) 2013-2017 Regents of the University of California.
#define NDN_RTM_STRING(x)
InterfaceType
Indicates the hardware type of a network interface.
#define NDN_NLMSG_STRING(x)
static AddressScope ifaScopeToAddressScope(uint8_t scope)
std::string to_string(const V &v)
#define NDN_LOG_TRACE(expression)
log at TRACE level
static AddressFamily ifaFamilyToAddressFamily(uint8_t family)
#define NDN_LOG_ERROR(expression)
log at ERROR level