31 #include <linux/if_addr.h>
32 #include <linux/if_link.h>
33 #include <net/if_arp.h>
35 #include <boost/range/adaptor/map.hpp>
36 #include <boost/range/algorithm_ext/push_back.hpp>
38 #ifndef RTEXT_FILTER_SKIP_STATS
39 #define RTEXT_FILTER_SKIP_STATS (1 << 3)
53 for (
auto group : {RTNLGRP_LINK,
54 RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV4_ROUTE,
55 RTNLGRP_IPV6_IFADDR, RTNLGRP_IPV6_ROUTE}) {
63 shared_ptr<const NetworkInterface>
66 for (
const auto& interface : m_interfaces | boost::adaptors::map_values) {
67 if (interface->getName() == ifname)
73 std::vector<shared_ptr<const NetworkInterface>>
76 std::vector<shared_ptr<const NetworkInterface>> v;
77 v.reserve(m_interfaces.size());
78 boost::push_back(v, m_interfaces | boost::adaptors::map_values);
83 NetworkMonitorImplNetlink::enumerateLinks()
86 m_phase = ENUMERATING_LINKS;
90 alignas(NLMSG_ALIGNTO) ifinfomsg ifi;
91 alignas(RTA_ALIGNTO) rtattr rta;
92 alignas(RTA_ALIGNTO) uint32_t rtext;
95 auto payload = make_shared<IfInfoMessage>();
96 payload->ifi.ifi_family = AF_UNSPEC;
97 payload->rta.rta_type = IFLA_EXT_MASK;
98 payload->rta.rta_len = RTA_LENGTH(
sizeof(payload->rtext));
101 m_rtnlSocket.
sendDumpRequest(RTM_GETLINK, payload.get(),
sizeof(IfInfoMessage),
103 [
this, payload] (
const auto& msg) { this->parseRtnlMessage(msg); });
107 NetworkMonitorImplNetlink::enumerateAddrs()
110 m_phase = ENUMERATING_ADDRS;
114 alignas(NLMSG_ALIGNTO) ifaddrmsg ifa;
117 auto payload = make_shared<IfAddrMessage>();
118 payload->ifa.ifa_family = AF_UNSPEC;
120 m_rtnlSocket.
sendDumpRequest(RTM_GETADDR, payload.get(),
sizeof(IfAddrMessage),
122 [
this, payload] (
const auto& msg) { this->parseRtnlMessage(msg); });
126 NetworkMonitorImplNetlink::enumerateRoutes()
133 m_phase = ENUMERATION_COMPLETE;
138 NetworkMonitorImplNetlink::parseRtnlMessage(
const NetlinkMessage& nlmsg)
140 switch (nlmsg->nlmsg_type) {
143 parseLinkMessage(nlmsg);
144 if (m_phase == ENUMERATION_COMPLETE)
150 parseAddressMessage(nlmsg);
151 if (m_phase == ENUMERATION_COMPLETE)
157 parseRouteMessage(nlmsg);
158 if (m_phase == ENUMERATION_COMPLETE)
163 parseDoneMessage(nlmsg);
167 parseErrorMessage(nlmsg);
178 case ARPHRD_LOOPBACK:
202 case RT_SCOPE_NOWHERE:
216 if (operState == linux_if::OPER_STATE_UP) {
219 else if (operState == linux_if::OPER_STATE_DORMANT) {
225 if ((flags & linux_if::FLAG_LOWER_UP) && !(flags & linux_if::FLAG_DORMANT))
227 else if (flags & IFF_UP)
234 #ifdef NDN_CXX_HAVE_NETLINK_EXT_ACK
236 parseExtAckAttributes(
const NetlinkMessageAttributes<nlattr>& attrs,
bool isError)
238 NDN_LOG_TRACE(
" message contains " << attrs.size() <<
" attributes");
240 auto msg = attrs.getAttributeByType<std::string>(NLMSGERR_ATTR_MSG);
241 if (msg && !msg->empty()) {
248 #endif // NDN_CXX_HAVE_NETLINK_EXT_ACK
251 NetworkMonitorImplNetlink::parseLinkMessage(
const NetlinkMessage& nlmsg)
253 const ifinfomsg* ifi = nlmsg.getPayload<ifinfomsg>();
254 if (ifi ==
nullptr) {
260 NDN_LOG_DEBUG(
" unhandled interface type " << ifi->ifi_type);
264 shared_ptr<NetworkInterface> interface;
265 auto it = m_interfaces.find(ifi->ifi_index);
266 if (it != m_interfaces.end()) {
267 interface = it->second;
268 BOOST_ASSERT(interface !=
nullptr);
269 BOOST_ASSERT(interface->getIndex() == ifi->ifi_index);
272 if (nlmsg->nlmsg_type == RTM_DELLINK) {
273 if (interface !=
nullptr) {
274 NDN_LOG_DEBUG(
" removing interface " << interface->getName());
275 m_interfaces.erase(it);
281 if (interface ==
nullptr) {
283 interface->setIndex(ifi->ifi_index);
286 interface->setFlags(ifi->ifi_flags);
288 auto attrs = nlmsg.getAttributes<rtattr>(ifi);
289 NDN_LOG_TRACE(
" message contains " << attrs.size() <<
" attributes");
291 auto address = attrs.getAttributeByType<ethernet::Address>(IFLA_ADDRESS);
293 interface->setEthernetAddress(*address);
295 auto broadcast = attrs.getAttributeByType<ethernet::Address>(IFLA_BROADCAST);
297 interface->setEthernetBroadcastAddress(*broadcast);
299 auto name = attrs.getAttributeByType<std::string>(IFLA_IFNAME);
301 interface->setName(*
name);
303 auto mtu = attrs.getAttributeByType<uint32_t>(IFLA_MTU);
305 interface->setMtu(*mtu);
307 auto state = attrs.getAttributeByType<uint8_t>(IFLA_OPERSTATE);
310 if (it == m_interfaces.end()) {
312 m_interfaces[interface->getIndex()] = interface;
318 NetworkMonitorImplNetlink::parseAddressMessage(
const NetlinkMessage& nlmsg)
320 const ifaddrmsg* ifa = nlmsg.getPayload<ifaddrmsg>();
321 if (ifa ==
nullptr) {
326 auto it = m_interfaces.find(ifa->ifa_index);
327 if (it == m_interfaces.end()) {
329 NDN_LOG_TRACE(
" unknown interface index " << ifa->ifa_index);
332 auto interface = it->second;
333 BOOST_ASSERT(interface !=
nullptr);
335 auto attrs = nlmsg.getAttributes<rtattr>(ifa);
336 NDN_LOG_TRACE(
" message contains " << attrs.size() <<
" attributes");
338 namespace ip = boost::asio::ip;
339 ip::address ipAddr, broadcastAddr;
340 if (ifa->ifa_family == AF_INET) {
341 auto v4 = attrs.getAttributeByType<ip::address_v4>(IFA_LOCAL);
345 v4 = attrs.getAttributeByType<ip::address_v4>(IFA_BROADCAST);
349 else if (ifa->ifa_family == AF_INET6) {
350 auto v6 = attrs.getAttributeByType<ip::address_v6>(IFA_ADDRESS);
352 if (v6->is_link_local())
353 v6->scope_id(ifa->ifa_index);
359 uint32_t flags = ifa->ifa_flags;
360 #ifdef NDN_CXX_HAVE_IFA_FLAGS
361 auto extFlags = attrs.getAttributeByType<uint32_t>(IFA_FLAGS);
364 #endif // NDN_CXX_HAVE_IFA_FLAGS
374 if (nlmsg->nlmsg_type == RTM_NEWADDR)
375 interface->addNetworkAddress(address);
376 else if (nlmsg->nlmsg_type == RTM_DELADDR)
377 interface->removeNetworkAddress(address);
381 NetworkMonitorImplNetlink::parseRouteMessage(
const NetlinkMessage& nlmsg)
387 NetworkMonitorImplNetlink::parseDoneMessage(
const NetlinkMessage& nlmsg)
389 const int* errcode = nlmsg.getPayload<
int>();
390 if (errcode ==
nullptr) {
397 #ifdef NDN_CXX_HAVE_NETLINK_EXT_ACK
398 if (nlmsg->nlmsg_flags & NLM_F_ACK_TLVS) {
399 parseExtAckAttributes(nlmsg.getAttributes<nlattr>(errcode), *errcode != 0);
401 #endif // NDN_CXX_HAVE_NETLINK_EXT_ACK
405 case ENUMERATING_LINKS:
409 case ENUMERATING_ADDRS:
419 NetworkMonitorImplNetlink::parseErrorMessage(
const NetlinkMessage& nlmsg)
421 const nlmsgerr* err = nlmsg.getPayload<nlmsgerr>();
422 if (err ==
nullptr) {
429 <<
" err=" << err->error <<
" " << std::strerror(
std::abs(err->error)));
431 #ifdef NDN_CXX_HAVE_NETLINK_EXT_ACK
432 if (!(nlmsg->nlmsg_flags & NLM_F_ACK_TLVS))
435 size_t errLen = NLMSG_LENGTH(
sizeof(nlmsgerr));
436 if (!(nlmsg->nlmsg_flags & NLM_F_CAPPED))
437 errLen += err->msg.nlmsg_len - NLMSG_HDRLEN;
439 if (nlmsg->nlmsg_len <= errLen)
442 auto nla =
reinterpret_cast<const nlattr*
>(
reinterpret_cast<const uint8_t*
>(&*nlmsg) + errLen);
443 auto attrs = NetlinkMessageAttributes<nlattr>(nla, nlmsg->nlmsg_len - errLen);
444 parseExtAckAttributes(attrs, err->error != 0);
445 #endif // NDN_CXX_HAVE_NETLINK_EXT_ACK