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; -*- */
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  : nReassembling(reassembler)
36 {
37 }
38 
40  : allowLocalFields(false)
41  , allowFragmentation(false)
42  , allowReassembly(false)
43 {
44 }
45 
47  : GenericLinkServiceCounters(m_reassembler)
48  , m_options(options)
49  , m_fragmenter(m_options.fragmenterOptions, this)
50  , m_reassembler(m_options.reassemblerOptions, this)
51  , m_lastSeqNo(-2)
52 {
53  m_reassembler.beforeTimeout.connect(bind([this] { ++this->nReassemblyTimeouts; }));
54 }
55 
56 void
57 GenericLinkService::doSendInterest(const Interest& interest)
58 {
59  lp::Packet lpPacket(interest.wireEncode());
60 
61  encodeLpFields(interest, lpPacket);
62 
63  this->sendNetPacket(std::move(lpPacket));
64 }
65 
66 void
67 GenericLinkService::doSendData(const Data& data)
68 {
69  lp::Packet lpPacket(data.wireEncode());
70 
71  encodeLpFields(data, lpPacket);
72 
73  this->sendNetPacket(std::move(lpPacket));
74 }
75 
76 void
77 GenericLinkService::doSendNack(const lp::Nack& nack)
78 {
79  lp::Packet lpPacket(nack.getInterest().wireEncode());
80  lpPacket.add<lp::NackField>(nack.getHeader());
81 
82  encodeLpFields(nack, lpPacket);
83 
84  this->sendNetPacket(std::move(lpPacket));
85 }
86 
87 void
88 GenericLinkService::encodeLpFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket)
89 {
90  if (m_options.allowLocalFields) {
91  shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = netPkt.getTag<lp::IncomingFaceIdTag>();
92  if (incomingFaceIdTag != nullptr) {
93  lpPacket.add<lp::IncomingFaceIdField>(*incomingFaceIdTag);
94  }
95  }
96 
97  shared_ptr<lp::CongestionMarkTag> congestionMarkTag = netPkt.getTag<lp::CongestionMarkTag>();
98  if (congestionMarkTag != nullptr) {
99  lpPacket.add<lp::CongestionMarkField>(*congestionMarkTag);
100  }
101 
102  shared_ptr<lp::HopCountTag> hopCountTag = netPkt.getTag<lp::HopCountTag>();
103  if (hopCountTag != nullptr) {
104  lpPacket.add<lp::HopCountTagField>(*hopCountTag);
105  }
106  else {
107  lpPacket.add<lp::HopCountTagField>(0);
108  }
109 }
110 
111 void
112 GenericLinkService::sendNetPacket(lp::Packet&& pkt)
113 {
114  std::vector<lp::Packet> frags;
115  const ssize_t mtu = this->getTransport()->getMtu();
116  if (m_options.allowFragmentation && mtu != MTU_UNLIMITED) {
117  bool isOk = false;
118  std::tie(isOk, frags) = m_fragmenter.fragmentPacket(pkt, mtu);
119  if (!isOk) {
120  // fragmentation failed (warning is logged by LpFragmenter)
121  ++this->nFragmentationErrors;
122  return;
123  }
124  }
125  else {
126  frags.push_back(pkt);
127  }
128 
129  if (frags.size() > 1) {
130  // sequence is needed only if packet is fragmented
131  this->assignSequences(frags);
132  }
133  else {
134  // even if indexed fragmentation is enabled, the fragmenter should not
135  // fragment the packet if it can fit in MTU
136  BOOST_ASSERT(frags.size() > 0);
137  BOOST_ASSERT(!frags.front().has<lp::FragIndexField>());
138  BOOST_ASSERT(!frags.front().has<lp::FragCountField>());
139  }
140 
141  for (const lp::Packet& frag : frags) {
142  Transport::Packet tp(frag.wireEncode());
143  if (mtu != MTU_UNLIMITED && tp.packet.size() > static_cast<size_t>(mtu)) {
144  ++this->nOutOverMtu;
145  NFD_LOG_FACE_WARN("attempt to send packet over MTU limit");
146  continue;
147  }
148  this->sendPacket(std::move(tp));
149  }
150 }
151 
152 void
153 GenericLinkService::assignSequence(lp::Packet& pkt)
154 {
155  pkt.set<lp::SequenceField>(++m_lastSeqNo);
156 }
157 
158 void
159 GenericLinkService::assignSequences(std::vector<lp::Packet>& pkts)
160 {
161  std::for_each(pkts.begin(), pkts.end(), bind(&GenericLinkService::assignSequence, this, _1));
162 }
163 
164 void
165 GenericLinkService::doReceivePacket(Transport::Packet&& packet)
166 {
167  try {
168  lp::Packet pkt(packet.packet);
169 
170  if (!pkt.has<lp::FragmentField>()) {
171  NFD_LOG_FACE_TRACE("received IDLE packet: DROP");
172  return;
173  }
174 
175  if ((pkt.has<lp::FragIndexField>() || pkt.has<lp::FragCountField>()) &&
176  !m_options.allowReassembly) {
177  NFD_LOG_FACE_WARN("received fragment, but reassembly disabled: DROP");
178  return;
179  }
180 
181  bool isReassembled = false;
182  Block netPkt;
183  lp::Packet firstPkt;
184  std::tie(isReassembled, netPkt, firstPkt) = m_reassembler.receiveFragment(packet.remoteEndpoint,
185  pkt);
186  if (isReassembled) {
187  this->decodeNetPacket(netPkt, firstPkt);
188  }
189  }
190  catch (const tlv::Error& e) {
191  ++this->nInLpInvalid;
192  NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
193  }
194 }
195 
196 void
197 GenericLinkService::decodeNetPacket(const Block& netPkt, const lp::Packet& firstPkt)
198 {
199  try {
200  switch (netPkt.type()) {
201  case tlv::Interest:
202  if (firstPkt.has<lp::NackField>()) {
203  this->decodeNack(netPkt, firstPkt);
204  }
205  else {
206  this->decodeInterest(netPkt, firstPkt);
207  }
208  break;
209  case tlv::Data:
210  this->decodeData(netPkt, firstPkt);
211  break;
212  default:
213  ++this->nInNetInvalid;
214  NFD_LOG_FACE_WARN("unrecognized network-layer packet TLV-TYPE " << netPkt.type() << ": DROP");
215  return;
216  }
217  }
218  catch (const tlv::Error& e) {
219  ++this->nInNetInvalid;
220  NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
221  }
222 }
223 
224 void
225 GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstPkt)
226 {
227  BOOST_ASSERT(netPkt.type() == tlv::Interest);
228  BOOST_ASSERT(!firstPkt.has<lp::NackField>());
229 
230  // forwarding expects Interest to be created with make_shared
231  auto interest = make_shared<Interest>(netPkt);
232 
233  // Increment HopCount
234  if (firstPkt.has<lp::HopCountTagField>()) {
235  interest->setTag(make_shared<lp::HopCountTag>(firstPkt.get<lp::HopCountTagField>() + 1));
236  }
237 
238  if (firstPkt.has<lp::NextHopFaceIdField>()) {
239  if (m_options.allowLocalFields) {
240  interest->setTag(make_shared<lp::NextHopFaceIdTag>(firstPkt.get<lp::NextHopFaceIdField>()));
241  }
242  else {
243  NFD_LOG_FACE_WARN("received NextHopFaceId, but local fields disabled: DROP");
244  return;
245  }
246  }
247 
248  if (firstPkt.has<lp::CachePolicyField>()) {
249  ++this->nInNetInvalid;
250  NFD_LOG_FACE_WARN("received CachePolicy with Interest: DROP");
251  return;
252  }
253 
254  if (firstPkt.has<lp::IncomingFaceIdField>()) {
255  NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
256  }
257 
258  if (firstPkt.has<lp::CongestionMarkField>()) {
259  interest->setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
260  }
261 
262  this->receiveInterest(*interest);
263 }
264 
265 void
266 GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt)
267 {
268  BOOST_ASSERT(netPkt.type() == tlv::Data);
269 
270  // forwarding expects Data to be created with make_shared
271  auto data = make_shared<Data>(netPkt);
272 
273  if (firstPkt.has<lp::HopCountTagField>()) {
274  data->setTag(make_shared<lp::HopCountTag>(firstPkt.get<lp::HopCountTagField>() + 1));
275  }
276 
277  if (firstPkt.has<lp::NackField>()) {
278  ++this->nInNetInvalid;
279  NFD_LOG_FACE_WARN("received Nack with Data: DROP");
280  return;
281  }
282 
283  if (firstPkt.has<lp::NextHopFaceIdField>()) {
284  ++this->nInNetInvalid;
285  NFD_LOG_FACE_WARN("received NextHopFaceId with Data: DROP");
286  return;
287  }
288 
289  if (firstPkt.has<lp::CachePolicyField>()) {
290  if (m_options.allowLocalFields) {
291  // In case of an invalid CachePolicyType, get<lp::CachePolicyField> will throw,
292  // so it's unnecessary to check here.
293  data->setTag(make_shared<lp::CachePolicyTag>(firstPkt.get<lp::CachePolicyField>()));
294  }
295  else {
296  NFD_LOG_FACE_WARN("received CachePolicy, but local fields disabled: IGNORE");
297  }
298  }
299 
300  if (firstPkt.has<lp::IncomingFaceIdField>()) {
301  NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
302  }
303 
304  if (firstPkt.has<lp::CongestionMarkField>()) {
305  data->setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
306  }
307 
308  this->receiveData(*data);
309 }
310 
311 void
312 GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt)
313 {
314  BOOST_ASSERT(netPkt.type() == tlv::Interest);
315  BOOST_ASSERT(firstPkt.has<lp::NackField>());
316 
317  lp::Nack nack((Interest(netPkt)));
318  nack.setHeader(firstPkt.get<lp::NackField>());
319 
320  if (firstPkt.has<lp::NextHopFaceIdField>()) {
321  ++this->nInNetInvalid;
322  NFD_LOG_FACE_WARN("received NextHopFaceId with Nack: DROP");
323  return;
324  }
325 
326  if (firstPkt.has<lp::CachePolicyField>()) {
327  ++this->nInNetInvalid;
328  NFD_LOG_FACE_WARN("received CachePolicy with Nack: DROP");
329  return;
330  }
331 
332  if (firstPkt.has<lp::IncomingFaceIdField>()) {
333  NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
334  }
335 
336  if (firstPkt.has<lp::CongestionMarkField>()) {
337  nack.setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
338  }
339 
340  this->receiveNack(nack);
341 }
342 
343 } // namespace face
344 } // namespace nfd
LpFragmenter::Options fragmenterOptions
options for fragmentation
void setTag(shared_ptr< T > tag) const
set a tag item
Definition: tag-host.hpp:80
signal::Signal< LpReassembler, Transport::EndpointId, size_t > beforeTimeout
signals before a partial packet is dropped due to timeout
shared_ptr< T > getTag() const
get a tag item
Definition: tag-host.hpp:67
#define NFD_LOG_FACE_TRACE(msg)
Log a message at TRACE level.
Definition: face-log.hpp:74
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:144
const ssize_t MTU_UNLIMITED
indicates the transport has no limit on payload size
Definition: transport.hpp:95
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:156
Nack & setHeader(const NackHeader &header)
Definition: nack.hpp:77
const Transport * getTransport() const
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
Class representing a wire element of NDN-TLV packet format.
Definition: block.hpp:43
represents an Interest packet
Definition: interest.hpp:42
const NackHeader & getHeader() const
Definition: nack.hpp:65
void sendPacket(Transport::Packet &&packet)
sends a lower-layer packet via Transport
bool has() const
Definition: packet.hpp:75
GenericLinkServiceCounters(const LpReassembler &reassembler)
represents a Network Nack
Definition: nack.hpp:40
provides a tag type for simple types
Definition: tag.hpp:58
FIELD::ValueType get(size_t index=0) const
Definition: packet.hpp:100
PacketCounter nOutOverMtu
count of outgoing LpPackets dropped due to exceeding MTU limit
Copyright (c) 2011-2015 Regents of the University of California.
Definition: ndn-common.hpp:40
void receiveNack(const lp::Nack &nack)
delivers received Nack to forwarding
ssize_t getMtu() const
Definition: transport.hpp:410
reassembles fragmented network-layer packets
counters provided by GenericLinkService
Options that control the behavior of GenericLinkService.
size_t wireEncode(EncodingImpl< TAG > &encoder) const
Fast encoding or block size estimation.
Definition: interest.cpp:217
void receiveData(const Data &data)
delivers received Data to forwarding
size_t wireEncode(EncodingImpl< TAG > &encoder, bool wantUnsignedPortionOnly=false) const
Fast encoding or block size estimation.
Definition: data.cpp:52
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
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:37
GenericLinkService(const Options &options=Options())
uint32_t type() const
Definition: block.hpp:324
const Interest & getInterest() const
Definition: nack.hpp:53
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:83
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
bool allowFragmentation
enables fragmentation