NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.5: NDN, CCN, CCNx, content centric networks
API Documentation
netlink-message.hpp
Go to the documentation of this file.
1 /* -*- 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 #ifndef NDN_NET_NETLINK_MESSAGE_HPP
25 #define NDN_NET_NETLINK_MESSAGE_HPP
26 
28 #include "ndn-cxx/net/ethernet.hpp"
29 
30 #ifndef NDN_CXX_HAVE_NETLINK
31 #error "This file should not be included ..."
32 #endif
33 
34 #include <linux/netlink.h>
35 #include <linux/rtnetlink.h>
36 #include <string.h>
37 
38 #include <cstring>
39 #include <map>
40 
41 #include <boost/asio/ip/address.hpp>
42 
43 namespace ndn {
44 namespace net {
45 
46 template<typename T>
47 constexpr size_t
48 getAttributeLength(const T* attr);
49 
50 template<>
51 constexpr size_t
52 getAttributeLength(const nlattr* attr)
53 {
54  return attr->nla_len;
55 }
56 
57 template<>
58 constexpr size_t
59 getAttributeLength(const rtattr* attr)
60 {
61  return attr->rta_len;
62 }
63 
64 template<typename T>
65 constexpr size_t
66 getAttributeLengthAligned(const T* attr);
67 
68 template<>
69 constexpr size_t
70 getAttributeLengthAligned(const nlattr* attr)
71 {
72  return NLA_ALIGN(attr->nla_len);
73 }
74 
75 template<>
76 constexpr size_t
77 getAttributeLengthAligned(const rtattr* attr)
78 {
79  return RTA_ALIGN(attr->rta_len);
80 }
81 
82 template<typename T>
83 constexpr uint16_t
84 getAttributeType(const T* attr);
85 
86 template<>
87 constexpr uint16_t
88 getAttributeType(const nlattr* attr)
89 {
90  return attr->nla_type & NLA_TYPE_MASK;
91 }
92 
93 template<>
94 constexpr uint16_t
95 getAttributeType(const rtattr* attr)
96 {
97  return attr->rta_type;
98 }
99 
100 template<typename T>
101 const uint8_t*
102 getAttributeValue(const T* attr);
103 
104 template<>
105 inline const uint8_t*
106 getAttributeValue(const nlattr* attr)
107 {
108  return reinterpret_cast<const uint8_t*>(attr) + NLA_HDRLEN;
109 }
110 
111 template<>
112 inline const uint8_t*
113 getAttributeValue(const rtattr* attr)
114 {
115  return reinterpret_cast<const uint8_t*>(RTA_DATA(const_cast<rtattr*>(attr)));
116 }
117 
118 template<typename T>
119 constexpr size_t
120 getAttributeValueLength(const T* attr);
121 
122 template<>
123 constexpr size_t
124 getAttributeValueLength(const nlattr* attr)
125 {
126  return attr->nla_len - NLA_HDRLEN;
127 }
128 
129 template<>
130 constexpr size_t
131 getAttributeValueLength(const rtattr* attr)
132 {
133  return RTA_PAYLOAD(attr);
134 }
135 
136 template<typename T>
138 
140 {
141 public:
142  explicit
143  NetlinkMessage(const uint8_t* buf, size_t buflen) noexcept
144  : m_msg(reinterpret_cast<const nlmsghdr*>(buf))
145  , m_length(buflen)
146  {
147  BOOST_ASSERT(buf != nullptr);
148  }
149 
150  const nlmsghdr&
151  operator*() const noexcept
152  {
153  return *m_msg;
154  }
155 
156  const nlmsghdr*
157  operator->() const noexcept
158  {
159  return m_msg;
160  }
161 
162  bool
163  isValid() const noexcept
164  {
165  return NLMSG_OK(m_msg, m_length);
166  }
167 
169  getNext() const noexcept
170  {
171  BOOST_ASSERT(isValid());
172 
173  // mimic NLMSG_NEXT
174  auto thisLen = NLMSG_ALIGN(m_msg->nlmsg_len);
175  return NetlinkMessage{reinterpret_cast<const uint8_t*>(m_msg) + thisLen, m_length - thisLen};
176  }
177 
178  template<typename T>
179  const T*
180  getPayload() const noexcept
181  {
182  BOOST_ASSERT(isValid());
183 
184  if (m_msg->nlmsg_len < NLMSG_LENGTH(sizeof(T)))
185  return nullptr;
186 
187  return reinterpret_cast<const T*>(NLMSG_DATA(const_cast<nlmsghdr*>(m_msg)));
188  }
189 
190  template<typename AttributeT, typename PayloadT>
192  getAttributes(const PayloadT* p) const noexcept
193  {
194  BOOST_ASSERT(isValid());
195 
196  auto begin = reinterpret_cast<const uint8_t*>(p) + NLMSG_ALIGN(sizeof(PayloadT));
197  auto length = NLMSG_PAYLOAD(m_msg, sizeof(PayloadT));
198  return NetlinkMessageAttributes<AttributeT>{reinterpret_cast<const AttributeT*>(begin), length};
199  }
200 
201 private:
202  const nlmsghdr* m_msg;
203  size_t m_length;
204 };
205 
206 template<typename T>
207 class NetlinkMessageAttributes
208 {
209  // empty type used to implement tag dispatching in getAttributeByType()
210  template<typename U>
211  struct AttrValueTypeTag {};
212 
213 public:
214  explicit
215  NetlinkMessageAttributes(const T* begin, size_t length) noexcept
216  {
217  for (; isAttrValid(begin, length); begin = getNextAttr(begin, length)) {
218  m_attrs[getAttributeType(begin)] = begin;
219  }
220  }
221 
222  size_t
223  size() const noexcept
224  {
225  return m_attrs.size();
226  }
227 
228  template<typename U>
229  optional<U>
230  getAttributeByType(uint16_t attrType) const
231  {
232  auto it = m_attrs.find(attrType);
233  if (it == m_attrs.end())
234  return nullopt;
235 
236  return convertAttrValue(getAttributeValue(it->second),
237  getAttributeValueLength(it->second),
238  AttrValueTypeTag<U>{});
239  }
240 
241 private:
242  static bool
243  isAttrValid(const T* attr, size_t nBytesRemaining) noexcept
244  {
245  return attr != nullptr &&
246  nBytesRemaining >= sizeof(T) &&
247  getAttributeLength(attr) >= sizeof(T) &&
248  getAttributeLength(attr) <= nBytesRemaining;
249  }
250 
251  static const T*
252  getNextAttr(const T* attr, size_t& nBytesRemaining) noexcept
253  {
254  auto len = getAttributeLengthAligned(attr);
255  if (len > nBytesRemaining) // prevent integer underflow
256  return nullptr;
257 
258  nBytesRemaining -= len;
259  return reinterpret_cast<const T*>(reinterpret_cast<const uint8_t*>(attr) + len);
260  }
261 
262  template<typename Integral>
263  static std::enable_if_t<std::is_integral<Integral>::value, optional<Integral>>
264  convertAttrValue(const uint8_t* val, size_t len, AttrValueTypeTag<Integral>)
265  {
266  if (len < sizeof(Integral))
267  return nullopt;
268 
269  Integral i;
270  std::memcpy(&i, val, sizeof(Integral));
271  return i;
272  }
273 
274  static optional<std::string>
275  convertAttrValue(const uint8_t* val, size_t len, AttrValueTypeTag<std::string>)
276  {
277  auto str = reinterpret_cast<const char*>(val);
278  if (::strnlen(str, len) < len)
279  return std::string(str);
280  else
281  return nullopt;
282  }
283 
284  static optional<ethernet::Address>
285  convertAttrValue(const uint8_t* val, size_t len, AttrValueTypeTag<ethernet::Address>)
286  {
287  if (len < ethernet::ADDR_LEN)
288  return nullopt;
289 
290  return ethernet::Address(val);
291  }
292 
293  template<typename IpAddress>
294  static std::enable_if_t<std::is_same<IpAddress, boost::asio::ip::address_v4>::value ||
295  std::is_same<IpAddress, boost::asio::ip::address_v6>::value, optional<IpAddress>>
296  convertAttrValue(const uint8_t* val, size_t len, AttrValueTypeTag<IpAddress>)
297  {
298  typename IpAddress::bytes_type bytes;
299  if (len < bytes.size())
300  return nullopt;
301 
302  std::copy_n(val, bytes.size(), bytes.begin());
303  return IpAddress(bytes);
304  }
305 
306 private:
307  std::map<uint16_t, const T*> m_attrs;
308 };
309 
310 } // namespace net
311 } // namespace ndn
312 
313 #endif // NDN_NET_NETLINK_MESSAGE_HPP
const T * getPayload() const noexcept
Copyright (c) 2011-2015 Regents of the University of California.
constexpr size_t getAttributeValueLength(const T *attr)
NetlinkMessageAttributes(const T *begin, size_t length) noexcept
const size_t ADDR_LEN
Octets in one Ethernet address.
Definition: ethernet.hpp:41
const nlmsghdr & operator *() const noexcept
constexpr uint16_t getAttributeType(const T *attr)
NetlinkMessage getNext() const noexcept
import common constructs for ndn-cxx library internal use
optional< U > getAttributeByType(uint16_t attrType) const
constexpr size_t getAttributeLength(const T *attr)
bool isValid() const noexcept
constexpr size_t getAttributeLengthAligned(const T *attr)
NetlinkMessage(const uint8_t *buf, size_t buflen) noexcept
const uint8_t * getAttributeValue(const T *attr)
const nullopt_t nullopt((nullopt_t::init()))
const nlmsghdr * operator->() const noexcept
NetlinkMessageAttributes< AttributeT > getAttributes(const PayloadT *p) const noexcept