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