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  if (m_options.allowLocalFields) {
62  encodeLocalFields(interest, lpPacket);
63  }
64 
65  this->sendNetPacket(std::move(lpPacket));
66 }
67 
68 void
69 GenericLinkService::doSendData(const Data& data)
70 {
71  lp::Packet lpPacket(data.wireEncode());
72 
73  if (m_options.allowLocalFields) {
74  encodeLocalFields(data, lpPacket);
75  }
76 
77  this->sendNetPacket(std::move(lpPacket));
78 }
79 
80 void
81 GenericLinkService::doSendNack(const lp::Nack& nack)
82 {
83  lp::Packet lpPacket(nack.getInterest().wireEncode());
84  lpPacket.add<lp::NackField>(nack.getHeader());
85 
86  if (m_options.allowLocalFields) {
87  encodeLocalFields(nack, lpPacket);
88  }
89 
90  this->sendNetPacket(std::move(lpPacket));
91 }
92 
93 void
94 GenericLinkService::encodeLocalFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket)
95 {
96  shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = netPkt.getTag<lp::IncomingFaceIdTag>();
97  if (incomingFaceIdTag != nullptr) {
98  lpPacket.add<lp::IncomingFaceIdField>(*incomingFaceIdTag);
99  }
100 }
101 
102 void
103 GenericLinkService::sendNetPacket(lp::Packet&& pkt)
104 {
105  std::vector<lp::Packet> frags;
106  const ssize_t mtu = this->getTransport()->getMtu();
107  if (m_options.allowFragmentation && mtu != MTU_UNLIMITED) {
108  bool isOk = false;
109  std::tie(isOk, frags) = m_fragmenter.fragmentPacket(pkt, mtu);
110  if (!isOk) {
111  // fragmentation failed (warning is logged by LpFragmenter)
112  ++this->nFragmentationErrors;
113  return;
114  }
115  }
116  else {
117  frags.push_back(pkt);
118  }
119 
120  if (frags.size() > 1) {
121  // sequence is needed only if packet is fragmented
122  this->assignSequences(frags);
123  }
124  else {
125  // even if indexed fragmentation is enabled, the fragmenter should not
126  // fragment the packet if it can fit in MTU
127  BOOST_ASSERT(frags.size() > 0);
128  BOOST_ASSERT(!frags.front().has<lp::FragIndexField>());
129  BOOST_ASSERT(!frags.front().has<lp::FragCountField>());
130  }
131 
132  for (const lp::Packet& frag : frags) {
133  Transport::Packet tp(frag.wireEncode());
134  if (mtu != MTU_UNLIMITED && tp.packet.size() > static_cast<size_t>(mtu)) {
135  ++this->nOutOverMtu;
136  NFD_LOG_FACE_WARN("attempt to send packet over MTU limit");
137  continue;
138  }
139  this->sendPacket(std::move(tp));
140  }
141 }
142 
143 void
144 GenericLinkService::assignSequence(lp::Packet& pkt)
145 {
146  pkt.set<lp::SequenceField>(++m_lastSeqNo);
147 }
148 
149 void
150 GenericLinkService::assignSequences(std::vector<lp::Packet>& pkts)
151 {
152  std::for_each(pkts.begin(), pkts.end(), bind(&GenericLinkService::assignSequence, this, _1));
153 }
154 
155 void
156 GenericLinkService::doReceivePacket(Transport::Packet&& packet)
157 {
158  try {
159  lp::Packet pkt(packet.packet);
160 
161  if (!pkt.has<lp::FragmentField>()) {
162  NFD_LOG_FACE_TRACE("received IDLE packet: DROP");
163  return;
164  }
165 
166  if ((pkt.has<lp::FragIndexField>() || pkt.has<lp::FragCountField>()) &&
167  !m_options.allowReassembly) {
168  NFD_LOG_FACE_WARN("received fragment, but reassembly disabled: DROP");
169  return;
170  }
171 
172  bool isReassembled = false;
173  Block netPkt;
174  lp::Packet firstPkt;
175  std::tie(isReassembled, netPkt, firstPkt) = m_reassembler.receiveFragment(packet.remoteEndpoint,
176  pkt);
177  if (isReassembled) {
178  this->decodeNetPacket(netPkt, firstPkt);
179  }
180  }
181  catch (const tlv::Error& e) {
182  ++this->nInLpInvalid;
183  NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
184  }
185 }
186 
187 void
188 GenericLinkService::decodeNetPacket(const Block& netPkt, const lp::Packet& firstPkt)
189 {
190  try {
191  switch (netPkt.type()) {
192  case tlv::Interest:
193  if (firstPkt.has<lp::NackField>()) {
194  this->decodeNack(netPkt, firstPkt);
195  }
196  else {
197  this->decodeInterest(netPkt, firstPkt);
198  }
199  break;
200  case tlv::Data:
201  this->decodeData(netPkt, firstPkt);
202  break;
203  default:
204  ++this->nInNetInvalid;
205  NFD_LOG_FACE_WARN("unrecognized network-layer packet TLV-TYPE " << netPkt.type() << ": DROP");
206  return;
207  }
208  }
209  catch (const tlv::Error& e) {
210  ++this->nInNetInvalid;
211  NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
212  }
213 }
214 
215 void
216 GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstPkt)
217 {
218  BOOST_ASSERT(netPkt.type() == tlv::Interest);
219  BOOST_ASSERT(!firstPkt.has<lp::NackField>());
220 
221  // forwarding expects Interest to be created with make_shared
222  auto interest = make_shared<Interest>(netPkt);
223 
224  if (firstPkt.has<lp::NextHopFaceIdField>()) {
225  if (m_options.allowLocalFields) {
226  interest->setTag(make_shared<lp::NextHopFaceIdTag>(firstPkt.get<lp::NextHopFaceIdField>()));
227  }
228  else {
229  NFD_LOG_FACE_WARN("received NextHopFaceId, but local fields disabled: DROP");
230  return;
231  }
232  }
233 
234  if (firstPkt.has<lp::CachePolicyField>()) {
235  ++this->nInNetInvalid;
236  NFD_LOG_FACE_WARN("received CachePolicy with Interest: DROP");
237  return;
238  }
239 
240  if (firstPkt.has<lp::IncomingFaceIdField>()) {
241  NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
242  }
243 
244  this->receiveInterest(*interest);
245 }
246 
247 void
248 GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt)
249 {
250  BOOST_ASSERT(netPkt.type() == tlv::Data);
251 
252  // forwarding expects Data to be created with make_shared
253  auto data = make_shared<Data>(netPkt);
254 
255  if (firstPkt.has<lp::NackField>()) {
256  ++this->nInNetInvalid;
257  NFD_LOG_FACE_WARN("received Nack with Data: DROP");
258  return;
259  }
260 
261  if (firstPkt.has<lp::NextHopFaceIdField>()) {
262  ++this->nInNetInvalid;
263  NFD_LOG_FACE_WARN("received NextHopFaceId with Data: DROP");
264  return;
265  }
266 
267  if (firstPkt.has<lp::CachePolicyField>()) {
268  if (m_options.allowLocalFields) {
269  // In case of an invalid CachePolicyType, get<lp::CachePolicyField> will throw,
270  // so it's unnecessary to check here.
271  data->setTag(make_shared<lp::CachePolicyTag>(firstPkt.get<lp::CachePolicyField>()));
272  }
273  else {
274  NFD_LOG_FACE_WARN("received CachePolicy, but local fields disabled: IGNORE");
275  }
276  }
277 
278  if (firstPkt.has<lp::IncomingFaceIdField>()) {
279  NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
280  }
281 
282  this->receiveData(*data);
283 }
284 
285 void
286 GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt)
287 {
288  BOOST_ASSERT(netPkt.type() == tlv::Interest);
289  BOOST_ASSERT(firstPkt.has<lp::NackField>());
290 
291  lp::Nack nack((Interest(netPkt)));
292  nack.setHeader(firstPkt.get<lp::NackField>());
293 
294  if (firstPkt.has<lp::NextHopFaceIdField>()) {
295  ++this->nInNetInvalid;
296  NFD_LOG_FACE_WARN("received NextHopFaceId with Nack: DROP");
297  return;
298  }
299 
300  if (firstPkt.has<lp::CachePolicyField>()) {
301  ++this->nInNetInvalid;
302  NFD_LOG_FACE_WARN("received CachePolicy with Nack: DROP");
303  return;
304  }
305 
306  if (firstPkt.has<lp::IncomingFaceIdField>()) {
307  NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
308  }
309 
310  this->receiveNack(nack);
311 }
312 
313 } // namespace face
314 } // namespace nfd
#define NFD_LOG_FACE_TRACE(msg)
Log a message at TRACE level.
Definition: face-log.hpp:74
const ssize_t MTU_UNLIMITED
indicates the transport has no limit on payload size
Definition: transport.hpp:95
ssize_t getMtu() const
Definition: transport.hpp:410
#define NFD_LOG_FACE_WARN(msg)
Log a message at WARN level.
Definition: face-log.hpp:83
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
Definition: algorithm.hpp:32
signal::Signal< LpReassembler, Transport::EndpointId, size_t > beforeTimeout
signals before a partial packet is dropped due to timeout
std::tuple< bool, std::vector< lp::Packet > > fragmentPacket(const lp::Packet &packet, size_t mtu)
fragments a network-layer packet into link-layer packets
reassembles fragmented network-layer packets
#define NFD_LOG_INIT(name)
Definition: logger.hpp:122
std::tuple< bool, Block, lp::Packet > receiveFragment(Transport::EndpointId remoteEndpoint, const lp::Packet &packet)
adds received fragment to buffer