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 
103 void
104 GenericLinkService::sendNetPacket(lp::Packet&& pkt)
105 {
106  std::vector<lp::Packet> frags;
107  const ssize_t mtu = this->getTransport()->getMtu();
108  if (m_options.allowFragmentation && mtu != MTU_UNLIMITED) {
109  bool isOk = false;
110  std::tie(isOk, frags) = m_fragmenter.fragmentPacket(pkt, mtu);
111  if (!isOk) {
112  // fragmentation failed (warning is logged by LpFragmenter)
113  ++this->nFragmentationErrors;
114  return;
115  }
116  }
117  else {
118  frags.push_back(pkt);
119  }
120 
121  if (frags.size() > 1) {
122  // sequence is needed only if packet is fragmented
123  this->assignSequences(frags);
124  }
125  else {
126  // even if indexed fragmentation is enabled, the fragmenter should not
127  // fragment the packet if it can fit in MTU
128  BOOST_ASSERT(frags.size() > 0);
129  BOOST_ASSERT(!frags.front().has<lp::FragIndexField>());
130  BOOST_ASSERT(!frags.front().has<lp::FragCountField>());
131  }
132 
133  for (const lp::Packet& frag : frags) {
134  Transport::Packet tp(frag.wireEncode());
135  if (mtu != MTU_UNLIMITED && tp.packet.size() > static_cast<size_t>(mtu)) {
136  ++this->nOutOverMtu;
137  NFD_LOG_FACE_WARN("attempt to send packet over MTU limit");
138  continue;
139  }
140  this->sendPacket(std::move(tp));
141  }
142 }
143 
144 void
145 GenericLinkService::assignSequence(lp::Packet& pkt)
146 {
147  pkt.set<lp::SequenceField>(++m_lastSeqNo);
148 }
149 
150 void
151 GenericLinkService::assignSequences(std::vector<lp::Packet>& pkts)
152 {
153  std::for_each(pkts.begin(), pkts.end(), bind(&GenericLinkService::assignSequence, this, _1));
154 }
155 
156 void
157 GenericLinkService::doReceivePacket(Transport::Packet&& packet)
158 {
159  try {
160  lp::Packet pkt(packet.packet);
161 
162  if (!pkt.has<lp::FragmentField>()) {
163  NFD_LOG_FACE_TRACE("received IDLE packet: DROP");
164  return;
165  }
166 
167  if ((pkt.has<lp::FragIndexField>() || pkt.has<lp::FragCountField>()) &&
168  !m_options.allowReassembly) {
169  NFD_LOG_FACE_WARN("received fragment, but reassembly disabled: DROP");
170  return;
171  }
172 
173  bool isReassembled = false;
174  Block netPkt;
175  lp::Packet firstPkt;
176  std::tie(isReassembled, netPkt, firstPkt) = m_reassembler.receiveFragment(packet.remoteEndpoint,
177  pkt);
178  if (isReassembled) {
179  this->decodeNetPacket(netPkt, firstPkt);
180  }
181  }
182  catch (const tlv::Error& e) {
183  ++this->nInLpInvalid;
184  NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
185  }
186 }
187 
188 void
189 GenericLinkService::decodeNetPacket(const Block& netPkt, const lp::Packet& firstPkt)
190 {
191  try {
192  switch (netPkt.type()) {
193  case tlv::Interest:
194  if (firstPkt.has<lp::NackField>()) {
195  this->decodeNack(netPkt, firstPkt);
196  }
197  else {
198  this->decodeInterest(netPkt, firstPkt);
199  }
200  break;
201  case tlv::Data:
202  this->decodeData(netPkt, firstPkt);
203  break;
204  default:
205  ++this->nInNetInvalid;
206  NFD_LOG_FACE_WARN("unrecognized network-layer packet TLV-TYPE " << netPkt.type() << ": DROP");
207  return;
208  }
209  }
210  catch (const tlv::Error& e) {
211  ++this->nInNetInvalid;
212  NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
213  }
214 }
215 
216 void
217 GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstPkt)
218 {
219  BOOST_ASSERT(netPkt.type() == tlv::Interest);
220  BOOST_ASSERT(!firstPkt.has<lp::NackField>());
221 
222  // forwarding expects Interest to be created with make_shared
223  auto interest = make_shared<Interest>(netPkt);
224 
225  if (firstPkt.has<lp::NextHopFaceIdField>()) {
226  if (m_options.allowLocalFields) {
227  interest->setTag(make_shared<lp::NextHopFaceIdTag>(firstPkt.get<lp::NextHopFaceIdField>()));
228  }
229  else {
230  NFD_LOG_FACE_WARN("received NextHopFaceId, but local fields disabled: DROP");
231  return;
232  }
233  }
234 
235  if (firstPkt.has<lp::CachePolicyField>()) {
236  ++this->nInNetInvalid;
237  NFD_LOG_FACE_WARN("received CachePolicy with Interest: DROP");
238  return;
239  }
240 
241  if (firstPkt.has<lp::IncomingFaceIdField>()) {
242  NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
243  }
244 
245  if (firstPkt.has<lp::CongestionMarkField>()) {
246  interest->setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
247  }
248 
249  this->receiveInterest(*interest);
250 }
251 
252 void
253 GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt)
254 {
255  BOOST_ASSERT(netPkt.type() == tlv::Data);
256 
257  // forwarding expects Data to be created with make_shared
258  auto data = make_shared<Data>(netPkt);
259 
260  if (firstPkt.has<lp::NackField>()) {
261  ++this->nInNetInvalid;
262  NFD_LOG_FACE_WARN("received Nack with Data: DROP");
263  return;
264  }
265 
266  if (firstPkt.has<lp::NextHopFaceIdField>()) {
267  ++this->nInNetInvalid;
268  NFD_LOG_FACE_WARN("received NextHopFaceId with Data: DROP");
269  return;
270  }
271 
272  if (firstPkt.has<lp::CachePolicyField>()) {
273  if (m_options.allowLocalFields) {
274  // In case of an invalid CachePolicyType, get<lp::CachePolicyField> will throw,
275  // so it's unnecessary to check here.
276  data->setTag(make_shared<lp::CachePolicyTag>(firstPkt.get<lp::CachePolicyField>()));
277  }
278  else {
279  NFD_LOG_FACE_WARN("received CachePolicy, but local fields disabled: IGNORE");
280  }
281  }
282 
283  if (firstPkt.has<lp::IncomingFaceIdField>()) {
284  NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
285  }
286 
287  if (firstPkt.has<lp::CongestionMarkField>()) {
288  data->setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
289  }
290 
291  this->receiveData(*data);
292 }
293 
294 void
295 GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt)
296 {
297  BOOST_ASSERT(netPkt.type() == tlv::Interest);
298  BOOST_ASSERT(firstPkt.has<lp::NackField>());
299 
300  lp::Nack nack((Interest(netPkt)));
301  nack.setHeader(firstPkt.get<lp::NackField>());
302 
303  if (firstPkt.has<lp::NextHopFaceIdField>()) {
304  ++this->nInNetInvalid;
305  NFD_LOG_FACE_WARN("received NextHopFaceId with Nack: DROP");
306  return;
307  }
308 
309  if (firstPkt.has<lp::CachePolicyField>()) {
310  ++this->nInNetInvalid;
311  NFD_LOG_FACE_WARN("received CachePolicy with Nack: DROP");
312  return;
313  }
314 
315  if (firstPkt.has<lp::IncomingFaceIdField>()) {
316  NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
317  }
318 
319  if (firstPkt.has<lp::CongestionMarkField>()) {
320  nack.setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
321  }
322 
323  this->receiveNack(nack);
324 }
325 
326 } // namespace face
327 } // 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:432
#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...
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