NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.3: NDN, CCN, CCNx, content centric networks
API Documentation
generic-link-service.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014-2017, Regents of the University of California,
4  * Arizona Board of Regents,
5  * Colorado State University,
6  * University Pierre & Marie Curie, Sorbonne University,
7  * Washington University in St. Louis,
8  * Beijing Institute of Technology,
9  * The University of Memphis.
10  *
11  * This file is part of NFD (Named Data Networking Forwarding Daemon).
12  * See AUTHORS.md for complete list of NFD authors and contributors.
13  *
14  * NFD is free software: you can redistribute it and/or modify it under the terms
15  * of the GNU General Public License as published by the Free Software Foundation,
16  * either version 3 of the License, or (at your option) any later version.
17  *
18  * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20  * PURPOSE. See the GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License along with
23  * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 #include "generic-link-service.hpp"
27 #include <ndn-cxx/lp/tags.hpp>
28 
29 namespace nfd {
30 namespace face {
31 
32 NFD_LOG_INIT("GenericLinkService");
33 
35  : allowLocalFields(false)
36  , allowFragmentation(false)
37  , allowReassembly(false)
38 {
39 }
40 
42  : m_options(options)
43  , m_fragmenter(m_options.fragmenterOptions, this)
44  , m_reassembler(m_options.reassemblerOptions, this)
45  , m_reliability(m_options.reliabilityOptions, this)
46  , m_lastSeqNo(-2)
47 {
48  m_reassembler.beforeTimeout.connect(bind([this] { ++this->nReassemblyTimeouts; }));
49  nReassembling.observe(&m_reassembler);
50 }
51 
52 void
54 {
55  m_options = options;
56  m_fragmenter.setOptions(m_options.fragmenterOptions);
57  m_reassembler.setOptions(m_options.reassemblerOptions);
58  m_reliability.setOptions(m_options.reliabilityOptions);
59 }
60 
61 void
62 GenericLinkService::requestIdlePacket()
63 {
64  // No need to request Acks to attach to this packet from LpReliability, as they are already
65  // attached in sendLpPacket
66  this->sendLpPacket({});
67 }
68 
69 void
70 GenericLinkService::sendLpPacket(lp::Packet&& pkt)
71 {
72  const ssize_t mtu = this->getTransport()->getMtu();
73  if (m_options.reliabilityOptions.isEnabled) {
74  m_reliability.piggyback(pkt, mtu);
75  }
76 
77  Transport::Packet tp(pkt.wireEncode());
78  if (mtu != MTU_UNLIMITED && tp.packet.size() > static_cast<size_t>(mtu)) {
79  ++this->nOutOverMtu;
80  NFD_LOG_FACE_WARN("attempted to send packet over MTU limit");
81  return;
82  }
83  this->sendPacket(std::move(tp));
84 }
85 
86 void
87 GenericLinkService::doSendInterest(const Interest& interest)
88 {
89  lp::Packet lpPacket(interest.wireEncode());
90 
91  encodeLpFields(interest, lpPacket);
92 
93  this->sendNetPacket(std::move(lpPacket));
94 }
95 
96 void
97 GenericLinkService::doSendData(const Data& data)
98 {
99  lp::Packet lpPacket(data.wireEncode());
100 
101  encodeLpFields(data, lpPacket);
102 
103  this->sendNetPacket(std::move(lpPacket));
104 }
105 
106 void
107 GenericLinkService::doSendNack(const lp::Nack& nack)
108 {
109  lp::Packet lpPacket(nack.getInterest().wireEncode());
110  lpPacket.add<lp::NackField>(nack.getHeader());
111 
112  encodeLpFields(nack, lpPacket);
113 
114  this->sendNetPacket(std::move(lpPacket));
115 }
116 
117 void
118 GenericLinkService::encodeLpFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket)
119 {
120  if (m_options.allowLocalFields) {
121  shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = netPkt.getTag<lp::IncomingFaceIdTag>();
122  if (incomingFaceIdTag != nullptr) {
123  lpPacket.add<lp::IncomingFaceIdField>(*incomingFaceIdTag);
124  }
125  }
126 
127  shared_ptr<lp::CongestionMarkTag> congestionMarkTag = netPkt.getTag<lp::CongestionMarkTag>();
128  if (congestionMarkTag != nullptr) {
129  lpPacket.add<lp::CongestionMarkField>(*congestionMarkTag);
130  }
131 
132  shared_ptr<lp::HopCountTag> hopCountTag = netPkt.getTag<lp::HopCountTag>();
133  if (hopCountTag != nullptr) {
134  lpPacket.add<lp::HopCountTagField>(*hopCountTag);
135  }
136  else {
137  lpPacket.add<lp::HopCountTagField>(0);
138  }
139 }
140 
141 void
142 GenericLinkService::sendNetPacket(lp::Packet&& pkt)
143 {
144  std::vector<lp::Packet> frags;
145  ssize_t mtu = this->getTransport()->getMtu();
146 
147  // Make space for feature fields in fragments
148  if (m_options.reliabilityOptions.isEnabled && mtu != MTU_UNLIMITED) {
150  BOOST_ASSERT(mtu > 0);
151  }
152 
153  if (m_options.allowFragmentation && mtu != MTU_UNLIMITED) {
154  bool isOk = false;
155  std::tie(isOk, frags) = m_fragmenter.fragmentPacket(pkt, mtu);
156  if (!isOk) {
157  // fragmentation failed (warning is logged by LpFragmenter)
158  ++this->nFragmentationErrors;
159  return;
160  }
161  }
162  else {
163  frags.push_back(std::move(pkt));
164  }
165 
166  if (frags.size() == 1) {
167  // even if indexed fragmentation is enabled, the fragmenter should not
168  // fragment the packet if it can fit in MTU
169  BOOST_ASSERT(!frags.front().has<lp::FragIndexField>());
170  BOOST_ASSERT(!frags.front().has<lp::FragCountField>());
171  }
172 
173  // Only assign sequences to fragments if packet contains more than 1 fragment
174  if (frags.size() > 1) {
175  // Assign sequences to all fragments
176  this->assignSequences(frags);
177  }
178 
179  if (m_options.reliabilityOptions.isEnabled && frags.front().has<lp::FragmentField>()) {
180  m_reliability.handleOutgoing(frags);
181  }
182 
183  for (lp::Packet& frag : frags) {
184  this->sendLpPacket(std::move(frag));
185  }
186 }
187 
188 void
189 GenericLinkService::assignSequence(lp::Packet& pkt)
190 {
191  pkt.set<lp::SequenceField>(++m_lastSeqNo);
192 }
193 
194 void
195 GenericLinkService::assignSequences(std::vector<lp::Packet>& pkts)
196 {
197  std::for_each(pkts.begin(), pkts.end(), bind(&GenericLinkService::assignSequence, this, _1));
198 }
199 
200 void
201 GenericLinkService::doReceivePacket(Transport::Packet&& packet)
202 {
203  try {
204  lp::Packet pkt(packet.packet);
205 
206  if (m_options.reliabilityOptions.isEnabled) {
207  m_reliability.processIncomingPacket(pkt);
208  }
209 
210  if (!pkt.has<lp::FragmentField>()) {
211  NFD_LOG_FACE_TRACE("received IDLE packet: DROP");
212  return;
213  }
214 
215  if ((pkt.has<lp::FragIndexField>() || pkt.has<lp::FragCountField>()) &&
216  !m_options.allowReassembly) {
217  NFD_LOG_FACE_WARN("received fragment, but reassembly disabled: DROP");
218  return;
219  }
220 
221  bool isReassembled = false;
222  Block netPkt;
223  lp::Packet firstPkt;
224  std::tie(isReassembled, netPkt, firstPkt) = m_reassembler.receiveFragment(packet.remoteEndpoint,
225  pkt);
226  if (isReassembled) {
227  this->decodeNetPacket(netPkt, firstPkt);
228  }
229  }
230  catch (const tlv::Error& e) {
231  ++this->nInLpInvalid;
232  NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
233  }
234 }
235 
236 void
237 GenericLinkService::decodeNetPacket(const Block& netPkt, const lp::Packet& firstPkt)
238 {
239  try {
240  switch (netPkt.type()) {
241  case tlv::Interest:
242  if (firstPkt.has<lp::NackField>()) {
243  this->decodeNack(netPkt, firstPkt);
244  }
245  else {
246  this->decodeInterest(netPkt, firstPkt);
247  }
248  break;
249  case tlv::Data:
250  this->decodeData(netPkt, firstPkt);
251  break;
252  default:
253  ++this->nInNetInvalid;
254  NFD_LOG_FACE_WARN("unrecognized network-layer packet TLV-TYPE " << netPkt.type() << ": DROP");
255  return;
256  }
257  }
258  catch (const tlv::Error& e) {
259  ++this->nInNetInvalid;
260  NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
261  }
262 }
263 
264 void
265 GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstPkt)
266 {
267  BOOST_ASSERT(netPkt.type() == tlv::Interest);
268  BOOST_ASSERT(!firstPkt.has<lp::NackField>());
269 
270  // forwarding expects Interest to be created with make_shared
271  auto interest = make_shared<Interest>(netPkt);
272 
273  // Increment HopCount
274  if (firstPkt.has<lp::HopCountTagField>()) {
275  interest->setTag(make_shared<lp::HopCountTag>(firstPkt.get<lp::HopCountTagField>() + 1));
276  }
277 
278  if (firstPkt.has<lp::NextHopFaceIdField>()) {
279  if (m_options.allowLocalFields) {
280  interest->setTag(make_shared<lp::NextHopFaceIdTag>(firstPkt.get<lp::NextHopFaceIdField>()));
281  }
282  else {
283  NFD_LOG_FACE_WARN("received NextHopFaceId, but local fields disabled: DROP");
284  return;
285  }
286  }
287 
288  if (firstPkt.has<lp::CachePolicyField>()) {
289  ++this->nInNetInvalid;
290  NFD_LOG_FACE_WARN("received CachePolicy with Interest: DROP");
291  return;
292  }
293 
294  if (firstPkt.has<lp::IncomingFaceIdField>()) {
295  NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
296  }
297 
298  if (firstPkt.has<lp::CongestionMarkField>()) {
299  interest->setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
300  }
301 
302  this->receiveInterest(*interest);
303 }
304 
305 void
306 GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt)
307 {
308  BOOST_ASSERT(netPkt.type() == tlv::Data);
309 
310  // forwarding expects Data to be created with make_shared
311  auto data = make_shared<Data>(netPkt);
312 
313  if (firstPkt.has<lp::HopCountTagField>()) {
314  data->setTag(make_shared<lp::HopCountTag>(firstPkt.get<lp::HopCountTagField>() + 1));
315  }
316 
317  if (firstPkt.has<lp::NackField>()) {
318  ++this->nInNetInvalid;
319  NFD_LOG_FACE_WARN("received Nack with Data: DROP");
320  return;
321  }
322 
323  if (firstPkt.has<lp::NextHopFaceIdField>()) {
324  ++this->nInNetInvalid;
325  NFD_LOG_FACE_WARN("received NextHopFaceId with Data: DROP");
326  return;
327  }
328 
329  if (firstPkt.has<lp::CachePolicyField>()) {
330  // CachePolicy is unprivileged and does not require allowLocalFields option.
331  // In case of an invalid CachePolicyType, get<lp::CachePolicyField> will throw,
332  // so it's unnecessary to check here.
333  data->setTag(make_shared<lp::CachePolicyTag>(firstPkt.get<lp::CachePolicyField>()));
334  }
335 
336  if (firstPkt.has<lp::IncomingFaceIdField>()) {
337  NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
338  }
339 
340  if (firstPkt.has<lp::CongestionMarkField>()) {
341  data->setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
342  }
343 
344  this->receiveData(*data);
345 }
346 
347 void
348 GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt)
349 {
350  BOOST_ASSERT(netPkt.type() == tlv::Interest);
351  BOOST_ASSERT(firstPkt.has<lp::NackField>());
352 
353  lp::Nack nack((Interest(netPkt)));
354  nack.setHeader(firstPkt.get<lp::NackField>());
355 
356  if (firstPkt.has<lp::NextHopFaceIdField>()) {
357  ++this->nInNetInvalid;
358  NFD_LOG_FACE_WARN("received NextHopFaceId with Nack: DROP");
359  return;
360  }
361 
362  if (firstPkt.has<lp::CachePolicyField>()) {
363  ++this->nInNetInvalid;
364  NFD_LOG_FACE_WARN("received CachePolicy with Nack: DROP");
365  return;
366  }
367 
368  if (firstPkt.has<lp::IncomingFaceIdField>()) {
369  NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
370  }
371 
372  if (firstPkt.has<lp::CongestionMarkField>()) {
373  nack.setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
374  }
375 
376  this->receiveNack(nack);
377 }
378 
379 } // namespace face
380 } // namespace nfd
LpFragmenter::Options fragmenterOptions
options for fragmentation
signal::Signal< LpReassembler, Transport::EndpointId, size_t > beforeTimeout
signals before a partial packet is dropped due to timeout
const NackHeader & getHeader() const
Definition: nack.hpp:65
void setOptions(const Options &options)
set options for reliability
void processIncomingPacket(const lp::Packet &pkt)
extract and parse all Acks and add Ack for contained Fragment (if any) to AckQueue ...
#define NFD_LOG_FACE_TRACE(msg)
Log a message at TRACE level.
Definition: face-log.hpp:79
bool allowLocalFields
enables encoding of IncomingFaceId, and decoding of NextHopFaceId and CachePolicy ...
Packet & set(const typename FIELD::ValueType &value)
remove all occurrences of FIELD, and add a FIELD with value
Definition: packet.hpp:141
const ssize_t MTU_UNLIMITED
indicates the transport has no limit on payload size
Definition: transport.hpp:95
void piggyback(lp::Packet &pkt, ssize_t mtu)
called by GenericLinkService to attach Acks onto an outgoing LpPacket
Base class to store tag information (e.g., inside Interest and Data packets)
Definition: tag-host.hpp:34
Packet & add(const typename FIELD::ValueType &value)
add a FIELD with value
Definition: packet.hpp:153
Nack & setHeader(const NackHeader &header)
Definition: nack.hpp:77
stores a packet along with the remote endpoint
Definition: transport.hpp:113
PacketCounter nReassemblyTimeouts
count of dropped partial network-layer packets due to reassembly timeout
LpReliability::Options reliabilityOptions
options for reliability
const Interest & getInterest() const
Definition: nack.hpp:53
Represents a TLV element of NDN packet format.
Definition: block.hpp:42
represents an Interest packet
Definition: interest.hpp:42
bool has() const
Definition: packet.hpp:78
void sendPacket(Transport::Packet &&packet)
sends a lower-layer packet via Transport
bool isEnabled
enables link-layer reliability
void setTag(shared_ptr< T > tag) const
set a tag item
Definition: tag-host.hpp:80
static constexpr size_t RESERVED_HEADER_SPACE
TxSequence TLV-TYPE (3 octets) + TxSequence TLV-LENGTH (1 octet) + sizeof(lp::Sequence) ...
represents a Network Nack
Definition: nack.hpp:40
void setOptions(const Options &options)
set options for fragmenter
provides a tag type for simple types
Definition: tag.hpp:58
size_t wireEncode(EncodingImpl< TAG > &encoder, bool wantUnsignedPortionOnly=false) const
Fast encoding or block size estimation.
Definition: data.cpp:48
ssize_t getMtu() const
Definition: transport.hpp:432
PacketCounter nOutOverMtu
count of outgoing LpPackets dropped due to exceeding MTU limit
FIELD::ValueType get(size_t index=0) const
Definition: packet.hpp:101
Copyright (c) 2011-2015 Regents of the University of California.
Definition: ndn-common.hpp:40
void handleOutgoing(std::vector< lp::Packet > &frags)
observe outgoing fragment(s) of a network packet and store for potential retransmission ...
const Transport * getTransport() const
void receiveNack(const lp::Nack &nack)
delivers received Nack to forwarding
size_t wireEncode(EncodingImpl< TAG > &encoder) const
Fast encoding or block size estimation.
Definition: interest.cpp:56
SizeCounter< LpReassembler > nReassembling
count of network-layer packets currently being reassembled
void setOptions(const Options &options)
set options for reassembler
void setOptions(const Options &options)
sets Options used by GenericLinkService
uint32_t type() const
Get TLV-TYPE.
Definition: block.hpp:235
Options that control the behavior of GenericLinkService.
void receiveData(const Data &data)
delivers received Data to forwarding
std::tuple< bool, Block, lp::Packet > receiveFragment(Transport::EndpointId remoteEndpoint, const lp::Packet &packet)
adds received fragment to buffer
PacketCounter nInNetInvalid
count of invalid reassembled network-layer packets dropped
shared_ptr< T > getTag() const
get a tag item
Definition: tag-host.hpp:67
std::tuple< bool, std::vector< lp::Packet > > fragmentPacket(const lp::Packet &packet, size_t mtu)
fragments a network-layer packet into link-layer packets
LpReassembler::Options reassemblerOptions
options for reassembly
#define NFD_LOG_INIT(name)
Definition: logger.hpp:34
Represents a Data packet.
Definition: data.hpp:35
GenericLinkService(const Options &options=Options())
represents an error in TLV encoding or decoding
Definition: tlv.hpp:50
#define NFD_LOG_FACE_WARN(msg)
Log a message at WARN level.
Definition: face-log.hpp:88
PacketCounter nInLpInvalid
count of invalid LpPackets dropped before reassembly
void receiveInterest(const Interest &interest)
delivers received Interest to forwarding
PacketCounter nFragmentationErrors
count of failed fragmentations