NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.5: NDN, CCN, CCNx, content centric networks
API Documentation
netlink-socket.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2020 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 
26 #include "ndn-cxx/util/logger.hpp"
27 #include "ndn-cxx/util/time.hpp"
28 
29 #include <linux/genetlink.h>
30 #include <sys/socket.h>
31 
32 #ifndef SOL_NETLINK
33 #define SOL_NETLINK 270
34 #endif
35 #ifndef NETLINK_CAP_ACK
36 #define NETLINK_CAP_ACK 10
37 #endif
38 #ifndef NETLINK_GET_STRICT_CHK
39 #define NETLINK_GET_STRICT_CHK 12
40 #endif
41 
42 NDN_LOG_INIT(ndn.NetworkMonitor);
43 
44 namespace ndn {
45 namespace net {
46 
47 // satisfies Asio's SettableSocketOption type requirements
48 template<int OptName>
50 {
51 public:
52  explicit
54  : m_value(val)
55  {
56  }
57 
58  template<typename Protocol>
59  int
60  level(const Protocol&) const
61  {
62  return SOL_NETLINK;
63  }
64 
65  template<typename Protocol>
66  int
67  name(const Protocol&) const
68  {
69  return OptName;
70  }
71 
72  template<typename Protocol>
73  const int*
74  data(const Protocol&) const
75  {
76  return &m_value;
77  }
78 
79  template<typename Protocol>
81  size(const Protocol&) const
82  {
83  return sizeof(m_value);
84  }
85 
86 private:
87  int m_value;
88 };
89 
90 NetlinkSocket::NetlinkSocket(boost::asio::io_service& io)
91  : m_sock(make_shared<boost::asio::generic::raw_protocol::socket>(io))
92  , m_pid(0)
93  , m_seqNum(static_cast<uint32_t>(time::system_clock::now().time_since_epoch().count()))
94  , m_buffer(16 * 1024) // 16 KiB
95 {
96 }
97 
99 {
100  boost::system::error_code ec;
101  m_sock->close(ec);
102 }
103 
104 void
105 NetlinkSocket::open(int protocol)
106 {
107  boost::asio::generic::raw_protocol proto(AF_NETLINK, protocol);
108  // open socket manually to set the close-on-exec flag atomically on creation
109  int fd = ::socket(proto.family(), proto.type() | SOCK_CLOEXEC, proto.protocol());
110  if (fd < 0) {
111  NDN_THROW_ERRNO(Error("Cannot create netlink socket"));
112  }
113 
114  boost::system::error_code ec;
115  m_sock->assign(proto, fd, ec);
116  if (ec) {
117  NDN_THROW(Error("Cannot assign descriptor: " + ec.message()));
118  }
119 
120  // increase socket receive buffer to 1MB to avoid losing messages
121  m_sock->set_option(boost::asio::socket_base::receive_buffer_size(1 * 1024 * 1024), ec);
122  if (ec) {
123  // not a fatal error
124  NDN_LOG_DEBUG("setting receive buffer size failed: " << ec.message());
125  }
126 
127  // enable control messages for received packets to get the destination group
128  m_sock->set_option(NetlinkSocketOption<NETLINK_PKTINFO>(true), ec);
129  if (ec) {
130  NDN_THROW(Error("Cannot enable NETLINK_PKTINFO: " + ec.message()));
131  }
132 
133  sockaddr_nl addr{};
134  addr.nl_family = AF_NETLINK;
135  if (::bind(m_sock->native_handle(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
136  NDN_THROW_ERRNO(Error("Cannot bind netlink socket"));
137  }
138 
139  // find out what pid has been assigned to us
140  socklen_t len = sizeof(addr);
141  if (::getsockname(m_sock->native_handle(), reinterpret_cast<sockaddr*>(&addr), &len) < 0) {
142  NDN_THROW_ERRNO(Error("Cannot obtain netlink socket address"));
143  }
144  if (len != sizeof(addr)) {
145  NDN_THROW(Error("Wrong address length (" + to_string(len) + ")"));
146  }
147  if (addr.nl_family != AF_NETLINK) {
148  NDN_THROW(Error("Wrong address family (" + to_string(addr.nl_family) + ")"));
149  }
150  m_pid = addr.nl_pid;
151  NDN_LOG_TRACE("our pid is " << m_pid);
152 
153  // tell the kernel it doesn't need to include the original payload in ACK messages
154  m_sock->set_option(NetlinkSocketOption<NETLINK_CAP_ACK>(true), ec);
155  if (ec) {
156  // not a fatal error
157  NDN_LOG_DEBUG("setting NETLINK_CAP_ACK failed: " << ec.message());
158  }
159 
160 #ifdef NDN_CXX_HAVE_NETLINK_EXT_ACK
161  // enable extended ACK reporting
162  m_sock->set_option(NetlinkSocketOption<NETLINK_EXT_ACK>(true), ec);
163  if (ec) {
164  // not a fatal error
165  NDN_LOG_DEBUG("setting NETLINK_EXT_ACK failed: " << ec.message());
166  }
167 #endif // NDN_CXX_HAVE_NETLINK_EXT_ACK
168 
169  // enable strict checking of get/dump requests
171  if (ec) {
172  // not a fatal error
173  NDN_LOG_DEBUG("setting NETLINK_GET_STRICT_CHK failed: " << ec.message());
174  }
175 }
176 
177 void
179 {
180  boost::system::error_code ec;
181  m_sock->set_option(NetlinkSocketOption<NETLINK_ADD_MEMBERSHIP>(group), ec);
182  if (ec) {
183  NDN_THROW(Error("Cannot join netlink group " + to_string(group) + ": " + ec.message()));
184  }
185 }
186 
187 void
189 {
191 }
192 
193 void
195 {
196  if (cb == nullptr) {
197  m_pendingRequests.erase(seq);
198  }
199  else {
200  bool wasEmpty = m_pendingRequests.empty();
201  m_pendingRequests.emplace(seq, std::move(cb));
202  if (wasEmpty)
203  asyncWait();
204  }
205 }
206 
207 std::string
209 {
210 #define NLMSG_STRINGIFY(x) case NLMSG_##x: return to_string(type) + "<" #x ">"
211  switch (type) {
212  NLMSG_STRINGIFY(NOOP);
213  NLMSG_STRINGIFY(ERROR);
214  NLMSG_STRINGIFY(DONE);
215  NLMSG_STRINGIFY(OVERRUN);
216  default:
217  return to_string(type);
218  }
219 #undef NLMSG_STRINGIFY
220 }
221 
222 void
223 NetlinkSocket::asyncWait()
224 {
225  // capture a copy of 'm_sock' to prevent its deallocation while the handler is still pending
226  auto handler = [this, sock = m_sock] (const boost::system::error_code& ec) {
227  if (!sock->is_open() || ec == boost::asio::error::operation_aborted) {
228  // socket was closed, ignore the error
229  NDN_LOG_DEBUG("netlink socket closed or operation aborted");
230  }
231  else if (ec) {
232  NDN_LOG_ERROR("read failed: " << ec.message());
233  NDN_THROW(Error("Netlink socket read error (" + ec.message() + ")"));
234  }
235  else {
236  receiveAndValidate();
237  if (!m_pendingRequests.empty())
238  asyncWait();
239  }
240  };
241 
242 #if BOOST_VERSION >= 106600
243  m_sock->async_wait(boost::asio::socket_base::wait_read, std::move(handler));
244 #else
245  m_sock->async_receive(boost::asio::null_buffers(),
246  [h = std::move(handler)] (const boost::system::error_code& ec, size_t) { h(ec); });
247 #endif
248 }
249 
250 void
251 NetlinkSocket::receiveAndValidate()
252 {
253  sockaddr_nl sender{};
254  iovec iov{};
255  iov.iov_base = m_buffer.data();
256  iov.iov_len = m_buffer.size();
257  uint8_t cmsgBuffer[CMSG_SPACE(sizeof(nl_pktinfo))];
258  msghdr msg{};
259  msg.msg_name = &sender;
260  msg.msg_namelen = sizeof(sender);
261  msg.msg_iov = &iov;
262  msg.msg_iovlen = 1;
263  msg.msg_control = cmsgBuffer;
264  msg.msg_controllen = sizeof(cmsgBuffer);
265 
266  ssize_t nBytesRead = ::recvmsg(m_sock->native_handle(), &msg, 0);
267  if (nBytesRead < 0) {
268  if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
269  // not a fatal error
270  NDN_LOG_DEBUG("recvmsg failed: " << std::strerror(errno));
271  return;
272  }
273  NDN_LOG_ERROR("recvmsg failed: " << std::strerror(errno));
274  NDN_THROW_ERRNO(Error("Netlink socket receive error"));
275  }
276 
277  NDN_LOG_TRACE("read " << nBytesRead << " bytes from netlink socket");
278 
279  if (msg.msg_flags & MSG_TRUNC) {
280  NDN_LOG_ERROR("truncated message");
281  NDN_THROW(Error("Received truncated netlink message"));
282  // TODO: grow the buffer and start over
283  }
284 
285  if (msg.msg_namelen >= sizeof(sender) && sender.nl_pid != 0) {
286  NDN_LOG_TRACE("ignoring message from pid=" << sender.nl_pid);
287  return;
288  }
289 
290  uint32_t nlGroup = 0;
291  for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
292  if (cmsg->cmsg_level == SOL_NETLINK &&
293  cmsg->cmsg_type == NETLINK_PKTINFO &&
294  cmsg->cmsg_len == CMSG_LEN(sizeof(nl_pktinfo))) {
295  const nl_pktinfo* pktinfo = reinterpret_cast<nl_pktinfo*>(CMSG_DATA(cmsg));
296  nlGroup = pktinfo->group;
297  }
298  }
299 
300  NetlinkMessage nlmsg(m_buffer.data(), static_cast<size_t>(nBytesRead));
301  for (; nlmsg.isValid(); nlmsg = nlmsg.getNext()) {
302  NDN_LOG_TRACE("parsing " << (nlmsg->nlmsg_flags & NLM_F_MULTI ? "multi-part " : "") <<
303  "message type=" << nlmsgTypeToString(nlmsg->nlmsg_type) <<
304  " len=" << nlmsg->nlmsg_len <<
305  " seq=" << nlmsg->nlmsg_seq <<
306  " pid=" << nlmsg->nlmsg_pid <<
307  " group=" << nlGroup);
308 
309  auto cbIt = m_pendingRequests.end();
310  if (nlGroup != 0) {
311  // it's a multicast notification
312  cbIt = m_pendingRequests.find(0);
313  }
314  else if (nlmsg->nlmsg_pid == m_pid) {
315  // it's for us
316  cbIt = m_pendingRequests.find(nlmsg->nlmsg_seq);
317  }
318  else {
319  NDN_LOG_TRACE(" pid mismatch, ignoring");
320  continue;
321  }
322 
323  if (cbIt == m_pendingRequests.end()) {
324  NDN_LOG_TRACE(" no handler registered, ignoring");
325  continue;
326  }
327  else if (nlmsg->nlmsg_flags & NLM_F_DUMP_INTR) {
328  NDN_LOG_ERROR("dump is inconsistent");
329  NDN_THROW(Error("Inconsistency detected in netlink dump"));
330  // TODO: discard the rest of the message and retry the dump
331  }
332  else {
333  // invoke the callback
334  BOOST_ASSERT(cbIt->second);
335  cbIt->second(nlmsg);
336  }
337 
338  // garbage collect the handler if we don't need it anymore:
339  // do it only if this is a reply message (i.e. not a notification) and either
340  // (1) it's not a multi-part message, in which case this is the only fragment, or
341  // (2) it's the last fragment of a multi-part message
342  if (nlGroup == 0 && (!(nlmsg->nlmsg_flags & NLM_F_MULTI) || nlmsg->nlmsg_type == NLMSG_DONE)) {
343  NDN_LOG_TRACE("removing handler for seq=" << nlmsg->nlmsg_seq);
344  BOOST_ASSERT(cbIt != m_pendingRequests.end());
345  m_pendingRequests.erase(cbIt);
346  }
347  }
348 }
349 
350 RtnlSocket::RtnlSocket(boost::asio::io_service& io)
351  : NetlinkSocket(io)
352 {
353 }
354 
355 void
357 {
358  NDN_LOG_TRACE("opening rtnetlink socket");
359  NetlinkSocket::open(NETLINK_ROUTE);
360 }
361 
362 void
363 RtnlSocket::sendDumpRequest(uint16_t nlmsgType, const void* payload, size_t payloadLen,
364  MessageCallback cb)
365 {
366  struct RtnlMessageHeader
367  {
368  alignas(NLMSG_ALIGNTO) nlmsghdr nlh;
369  };
370  static_assert(sizeof(RtnlMessageHeader) == NLMSG_HDRLEN, "");
371 
372  auto hdr = make_shared<RtnlMessageHeader>();
373  hdr->nlh.nlmsg_len = sizeof(RtnlMessageHeader) + payloadLen;
374  hdr->nlh.nlmsg_type = nlmsgType;
375  hdr->nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
376  hdr->nlh.nlmsg_seq = ++m_seqNum;
377  hdr->nlh.nlmsg_pid = m_pid;
378 
379  registerRequestCallback(hdr->nlh.nlmsg_seq, std::move(cb));
380 
381  std::array<boost::asio::const_buffer, 2> bufs = {
382  boost::asio::buffer(hdr.get(), sizeof(RtnlMessageHeader)),
383  boost::asio::buffer(payload, payloadLen)
384  };
385  m_sock->async_send(bufs,
386  // capture 'hdr' to prevent its premature deallocation
387  [this, hdr] (const boost::system::error_code& ec, size_t) {
388  if (!ec) {
389  NDN_LOG_TRACE("sent dump request type=" << nlmsgTypeToString(hdr->nlh.nlmsg_type)
390  << " seq=" << hdr->nlh.nlmsg_seq);
391  }
392  else if (ec != boost::asio::error::operation_aborted) {
393  NDN_LOG_ERROR("send failed: " << ec.message());
394  NDN_THROW(Error("Failed to send netlink request (" + ec.message() + ")"));
395  }
396  });
397 }
398 
399 std::string
400 RtnlSocket::nlmsgTypeToString(uint16_t type) const
401 {
402 #define RTM_STRINGIFY(x) case RTM_##x: return to_string(type) + "<" #x ">"
403  switch (type) {
404  RTM_STRINGIFY(NEWLINK);
405  RTM_STRINGIFY(DELLINK);
406  RTM_STRINGIFY(GETLINK);
407  RTM_STRINGIFY(NEWADDR);
408  RTM_STRINGIFY(DELADDR);
409  RTM_STRINGIFY(GETADDR);
410  RTM_STRINGIFY(NEWROUTE);
411  RTM_STRINGIFY(DELROUTE);
412  RTM_STRINGIFY(GETROUTE);
413  default:
415  }
416 #undef RTM_STRINGIFY
417 }
418 
419 GenlSocket::GenlSocket(boost::asio::io_service& io)
420  : NetlinkSocket(io)
421 {
422  m_cachedFamilyIds["nlctrl"] = GENL_ID_CTRL;
423 }
424 
425 void
427 {
428  NDN_LOG_TRACE("opening genetlink socket");
429  NetlinkSocket::open(NETLINK_GENERIC);
430 }
431 
432 void
433 GenlSocket::sendRequest(const std::string& familyName, uint8_t command,
434  const void* payload, size_t payloadLen,
435  MessageCallback messageCb, std::function<void()> errorCb)
436 {
437  auto it = m_cachedFamilyIds.find(familyName);
438  if (it != m_cachedFamilyIds.end()) {
439  if (it->second >= GENL_MIN_ID) {
440  sendRequest(it->second, command, payload, payloadLen, std::move(messageCb));
441  }
442  else if (errorCb) {
443  errorCb();
444  }
445  return;
446  }
447 
448  auto ret = m_familyResolvers.emplace(std::piecewise_construct,
449  std::forward_as_tuple(familyName),
450  std::forward_as_tuple(familyName, *this));
451  auto& resolver = ret.first->second;
452  if (ret.second) {
453  // cache the result
454  resolver.onResolved.connectSingleShot([=] (uint16_t familyId) {
455  m_cachedFamilyIds[familyName] = familyId;
456  });
457  resolver.onError.connectSingleShot([=] {
458  m_cachedFamilyIds[familyName] = 0;
459  });
460  }
461  resolver.onResolved.connectSingleShot([=, cb = std::move(messageCb)] (uint16_t familyId) {
462  sendRequest(familyId, command, payload, payloadLen, std::move(cb));
463  });
464  if (errorCb) {
465  resolver.onError.connectSingleShot(std::move(errorCb));
466  }
467 }
468 
469 void
470 GenlSocket::sendRequest(uint16_t familyId, uint8_t command,
471  const void* payload, size_t payloadLen, MessageCallback cb)
472 {
473  struct GenlMessageHeader
474  {
475  alignas(NLMSG_ALIGNTO) nlmsghdr nlh;
476  alignas(NLMSG_ALIGNTO) genlmsghdr genlh;
477  };
478  static_assert(sizeof(GenlMessageHeader) == NLMSG_SPACE(GENL_HDRLEN), "");
479 
480  auto hdr = make_shared<GenlMessageHeader>();
481  hdr->nlh.nlmsg_len = sizeof(GenlMessageHeader) + payloadLen;
482  hdr->nlh.nlmsg_type = familyId;
483  hdr->nlh.nlmsg_flags = NLM_F_REQUEST;
484  hdr->nlh.nlmsg_seq = ++m_seqNum;
485  hdr->nlh.nlmsg_pid = m_pid;
486  hdr->genlh.cmd = command;
487  hdr->genlh.version = 1;
488 
489  registerRequestCallback(hdr->nlh.nlmsg_seq, std::move(cb));
490 
491  std::array<boost::asio::const_buffer, 2> bufs = {
492  boost::asio::buffer(hdr.get(), sizeof(GenlMessageHeader)),
493  boost::asio::buffer(payload, payloadLen)
494  };
495  m_sock->async_send(bufs,
496  // capture 'hdr' to prevent its premature deallocation
497  [this, hdr] (const boost::system::error_code& ec, size_t) {
498  if (!ec) {
499  NDN_LOG_TRACE("sent genl request type=" << nlmsgTypeToString(hdr->nlh.nlmsg_type) <<
500  " cmd=" << static_cast<unsigned>(hdr->genlh.cmd) <<
501  " seq=" << hdr->nlh.nlmsg_seq);
502  }
503  else if (ec != boost::asio::error::operation_aborted) {
504  NDN_LOG_ERROR("send failed: " << ec.message());
505  NDN_THROW(Error("Failed to send netlink request (" + ec.message() + ")"));
506  }
507  });
508 }
509 
511  : m_sock(socket)
512  , m_family(std::move(familyName))
513 {
514  if (m_family.size() >= GENL_NAMSIZ) {
515  NDN_THROW(std::invalid_argument("netlink family name '" + m_family + "' too long"));
516  }
517 
518  NDN_LOG_TRACE("resolving netlink family " << m_family);
519  asyncResolve();
520 }
521 
522 void
523 GenlFamilyResolver::asyncResolve()
524 {
525  struct FamilyNameAttribute
526  {
527  alignas(NLA_ALIGNTO) nlattr nla;
528  alignas(NLA_ALIGNTO) char name[GENL_NAMSIZ];
529  };
530 
531  auto attr = make_shared<FamilyNameAttribute>();
532  attr->nla.nla_type = CTRL_ATTR_FAMILY_NAME;
533  attr->nla.nla_len = NLA_HDRLEN + m_family.size() + 1;
534  std::strncpy(attr->name, m_family.data(), GENL_NAMSIZ - 1);
535 
536  m_sock.sendRequest(GENL_ID_CTRL, CTRL_CMD_GETFAMILY, attr.get(), attr->nla.nla_len,
537  // capture 'attr' to prevent its premature deallocation
538  [this, attr] (const auto& msg) { this->handleResolve(msg); });
539 }
540 
541 void
542 GenlFamilyResolver::handleResolve(const NetlinkMessage& nlmsg)
543 {
544  switch (nlmsg->nlmsg_type) {
545  case NLMSG_ERROR: {
546  const nlmsgerr* err = nlmsg.getPayload<nlmsgerr>();
547  if (err == nullptr) {
548  NDN_LOG_WARN("malformed nlmsgerr");
549  }
550  else if (err->error != 0) {
551  NDN_LOG_DEBUG(" failed to resolve netlink family " << m_family
552  << ": " << std::strerror(std::abs(err->error)));
553  }
554  onError();
555  break;
556  }
557 
558  case GENL_ID_CTRL: {
559  const genlmsghdr* genlh = nlmsg.getPayload<genlmsghdr>();
560  if (genlh == nullptr) {
561  NDN_LOG_WARN("malformed genlmsghdr");
562  return onError();
563  }
564  if (genlh->cmd != CTRL_CMD_NEWFAMILY) {
565  NDN_LOG_WARN("unexpected genl cmd=" << static_cast<unsigned>(genlh->cmd));
566  return onError();
567  }
568 
569  auto attrs = nlmsg.getAttributes<nlattr>(genlh);
570  auto familyName = attrs.getAttributeByType<std::string>(CTRL_ATTR_FAMILY_NAME);
571  if (familyName && *familyName != m_family) {
572  NDN_LOG_WARN("CTRL_ATTR_FAMILY_NAME mismatch: " << *familyName << " != " << m_family);
573  return onError();
574  }
575  auto familyId = attrs.getAttributeByType<uint16_t>(CTRL_ATTR_FAMILY_ID);
576  if (!familyId) {
577  NDN_LOG_WARN("missing CTRL_ATTR_FAMILY_ID");
578  return onError();
579  }
580  if (*familyId < GENL_MIN_ID) {
581  NDN_LOG_WARN("invalid CTRL_ATTR_FAMILY_ID=" << *familyId);
582  return onError();
583  }
584 
585  NDN_LOG_TRACE(" resolved netlink family name=" << m_family << " id=" << *familyId);
586  onResolved(*familyId);
587  break;
588  }
589 
590  default: {
591  NDN_LOG_WARN("unexpected message type");
592  onError();
593  break;
594  }
595  }
596 }
597 
598 std::string
599 GenlSocket::nlmsgTypeToString(uint16_t type) const
600 {
601  if (type >= GENL_MIN_ID) {
602  for (const auto& p : m_cachedFamilyIds) {
603  if (p.second == type) {
604  return to_string(type) + "<" + p.first + ">";
605  }
606  }
607  }
608 
610 }
611 
612 } // namespace net
613 } // namespace ndn
const T * getPayload() const noexcept
Copyright (c) 2011-2015 Regents of the University of California.
shared_ptr< boost::asio::generic::raw_protocol::socket > m_sock
netlink socket descriptor
util::Signal< GenlFamilyResolver > onError
Definition: block.hpp:32
std::string to_string(const T &val)
Definition: backports.hpp:86
span_CONFIG_SIZE_TYPE size_t
Definition: span-lite.hpp:565
#define NDN_LOG_WARN(expression)
Definition: logger.hpp:101
#define NDN_LOG_DEBUG(expression)
Definition: logger.hpp:99
STL namespace.
RtnlSocket(boost::asio::io_service &io)
NetlinkMessage getNext() const noexcept
void sendDumpRequest(uint16_t nlmsgType, const void *payload, size_t payloadLen, MessageCallback cb)
constexpr duration< Rep, Period > abs(duration< Rep, Period > d)
Definition: time.hpp:58
#define NDN_THROW(e)
Definition: exception.hpp:61
#define NDN_LOG_ERROR(expression)
Definition: logger.hpp:102
std::string nlmsgTypeToString(uint16_t type) const final
void sendRequest(const std::string &familyName, uint8_t command, const void *payload, size_t payloadLen, MessageCallback messageCb, std::function< void()> errorCb)
std::size_t size(const Protocol &) const
uint32_t m_seqNum
sequence number of the last netlink request sent to the kernel
void open(int protocol)
int level(const Protocol &) const
#define NDN_LOG_TRACE(expression)
Definition: logger.hpp:98
std::string nlmsgTypeToString(uint16_t type) const final
void registerRequestCallback(uint32_t seq, MessageCallback cb)
bool isValid() const noexcept
NetworkMonitor::Error Error
GenlSocket(boost::asio::io_service &io)
const int * data(const Protocol &) const
int name(const Protocol &) const
void registerNotificationCallback(MessageCallback cb)
#define NDN_LOG_INIT(name)
declare a log module
Definition: logger.hpp:81
NetlinkSocket(boost::asio::io_service &io)
std::function< void(const NetlinkMessage &)> MessageCallback
Catch-all error for socket component errors that don&#39;t fit in other categories.
Definition: base.hpp:83
virtual std::string nlmsgTypeToString(uint16_t type) const
uint32_t m_pid
port ID of this socket
InputBuffers bufs
util::Signal< GenlFamilyResolver, uint16_t > onResolved
#define NDN_THROW_ERRNO(e)
Definition: exception.hpp:68
GenlFamilyResolver(std::string familyName, GenlSocket &socket)
NetlinkMessageAttributes< AttributeT > getAttributes(const PayloadT *p) const noexcept