blob: c634484649670a20474301d9cc4f2c08c92c48d0 [file] [log] [blame]
Eric Newberrya98bf932015-09-21 00:58:47 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Eric Newberry7b0071e2017-07-03 17:33:31 +00002/*
Eric Newberryb49313d2017-12-24 20:22:27 -07003 * Copyright (c) 2014-2018, Regents of the University of California,
Eric Newberrya98bf932015-09-21 00:58:47 -07004 * 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"
Eric Newberryb49313d2017-12-24 20:22:27 -070027
Junxiao Shicbc8e942016-09-06 03:17:45 +000028#include <ndn-cxx/lp/tags.hpp>
Eric Newberrya98bf932015-09-21 00:58:47 -070029
Eric Newberryb49313d2017-12-24 20:22:27 -070030#include <cmath>
31
Eric Newberrya98bf932015-09-21 00:58:47 -070032namespace nfd {
33namespace face {
34
35NFD_LOG_INIT("GenericLinkService");
36
Eric Newberryb49313d2017-12-24 20:22:27 -070037constexpr uint32_t DEFAULT_CONGESTION_THRESHOLD_DIVISOR = 2;
38
Eric Newberry86d31872015-09-23 16:24:59 -070039GenericLinkService::Options::Options()
40 : allowLocalFields(false)
Eric Newberry4c3e6b82015-11-10 16:48:42 -070041 , allowFragmentation(false)
42 , allowReassembly(false)
Eric Newberryb49313d2017-12-24 20:22:27 -070043 , allowCongestionMarking(false)
44 , baseCongestionMarkingInterval(time::milliseconds(100)) // Interval from RFC 8289 (CoDel)
45 , defaultCongestionThreshold(65536) // This default value works well for a queue capacity of 200KiB
Eric Newberry86d31872015-09-23 16:24:59 -070046{
47}
48
49GenericLinkService::GenericLinkService(const GenericLinkService::Options& options)
Eric Newberry73bcad32017-04-25 17:57:35 -070050 : m_options(options)
Eric Newberry4c3e6b82015-11-10 16:48:42 -070051 , m_fragmenter(m_options.fragmenterOptions, this)
52 , m_reassembler(m_options.reassemblerOptions, this)
Eric Newberry185ab292017-03-28 06:45:39 +000053 , m_reliability(m_options.reliabilityOptions, this)
Eric Newberry4c3e6b82015-11-10 16:48:42 -070054 , m_lastSeqNo(-2)
Eric Newberryb49313d2017-12-24 20:22:27 -070055 , m_nextMarkTime(time::steady_clock::TimePoint::max())
56 , m_lastMarkTime(time::steady_clock::TimePoint::min())
57 , m_nMarkedSinceInMarkingState(0)
Eric Newberry86d31872015-09-23 16:24:59 -070058{
Junxiao Shi0de23a22015-12-03 20:07:02 +000059 m_reassembler.beforeTimeout.connect(bind([this] { ++this->nReassemblyTimeouts; }));
Eric Newberry41aba102017-11-01 16:42:13 -070060 m_reliability.onDroppedInterest.connect([this] (const Interest& i) { this->notifyDroppedInterest(i); });
Eric Newberry73bcad32017-04-25 17:57:35 -070061 nReassembling.observe(&m_reassembler);
Eric Newberry86d31872015-09-23 16:24:59 -070062}
63
Eric Newberrya98bf932015-09-21 00:58:47 -070064void
Eric Newberry185ab292017-03-28 06:45:39 +000065GenericLinkService::setOptions(const GenericLinkService::Options& options)
66{
67 m_options = options;
68 m_fragmenter.setOptions(m_options.fragmenterOptions);
69 m_reassembler.setOptions(m_options.reassemblerOptions);
70 m_reliability.setOptions(m_options.reliabilityOptions);
71}
72
73void
74GenericLinkService::requestIdlePacket()
75{
76 // No need to request Acks to attach to this packet from LpReliability, as they are already
77 // attached in sendLpPacket
78 this->sendLpPacket({});
79}
80
81void
82GenericLinkService::sendLpPacket(lp::Packet&& pkt)
83{
84 const ssize_t mtu = this->getTransport()->getMtu();
Eric Newberryb49313d2017-12-24 20:22:27 -070085
Eric Newberry185ab292017-03-28 06:45:39 +000086 if (m_options.reliabilityOptions.isEnabled) {
87 m_reliability.piggyback(pkt, mtu);
88 }
89
Eric Newberryb49313d2017-12-24 20:22:27 -070090 if (m_options.allowCongestionMarking) {
91 checkCongestionLevel(pkt);
92 }
93
Eric Newberry185ab292017-03-28 06:45:39 +000094 Transport::Packet tp(pkt.wireEncode());
95 if (mtu != MTU_UNLIMITED && tp.packet.size() > static_cast<size_t>(mtu)) {
96 ++this->nOutOverMtu;
97 NFD_LOG_FACE_WARN("attempted to send packet over MTU limit");
98 return;
99 }
100 this->sendPacket(std::move(tp));
101}
102
103void
Eric Newberrya98bf932015-09-21 00:58:47 -0700104GenericLinkService::doSendInterest(const Interest& interest)
105{
106 lp::Packet lpPacket(interest.wireEncode());
Junxiao Shi0de23a22015-12-03 20:07:02 +0000107
Eric Newberryee400b52016-11-24 14:12:48 +0000108 encodeLpFields(interest, lpPacket);
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700109
Eric Newberry41aba102017-11-01 16:42:13 -0700110 this->sendNetPacket(std::move(lpPacket), true);
Eric Newberrya98bf932015-09-21 00:58:47 -0700111}
112
113void
114GenericLinkService::doSendData(const Data& data)
115{
116 lp::Packet lpPacket(data.wireEncode());
Junxiao Shi0de23a22015-12-03 20:07:02 +0000117
Eric Newberryee400b52016-11-24 14:12:48 +0000118 encodeLpFields(data, lpPacket);
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700119
Eric Newberry41aba102017-11-01 16:42:13 -0700120 this->sendNetPacket(std::move(lpPacket), false);
Eric Newberrya98bf932015-09-21 00:58:47 -0700121}
122
123void
124GenericLinkService::doSendNack(const lp::Nack& nack)
125{
126 lp::Packet lpPacket(nack.getInterest().wireEncode());
127 lpPacket.add<lp::NackField>(nack.getHeader());
Junxiao Shi0de23a22015-12-03 20:07:02 +0000128
Eric Newberryee400b52016-11-24 14:12:48 +0000129 encodeLpFields(nack, lpPacket);
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700130
Eric Newberry41aba102017-11-01 16:42:13 -0700131 this->sendNetPacket(std::move(lpPacket), false);
Eric Newberrya98bf932015-09-21 00:58:47 -0700132}
133
Junxiao Shi0de23a22015-12-03 20:07:02 +0000134void
Eric Newberry41aba102017-11-01 16:42:13 -0700135GenericLinkService::encodeLpFields(const ndn::PacketBase& netPkt, lp::Packet& lpPacket)
Eric Newberry86d31872015-09-23 16:24:59 -0700136{
Eric Newberryee400b52016-11-24 14:12:48 +0000137 if (m_options.allowLocalFields) {
138 shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = netPkt.getTag<lp::IncomingFaceIdTag>();
139 if (incomingFaceIdTag != nullptr) {
140 lpPacket.add<lp::IncomingFaceIdField>(*incomingFaceIdTag);
141 }
142 }
143
144 shared_ptr<lp::CongestionMarkTag> congestionMarkTag = netPkt.getTag<lp::CongestionMarkTag>();
145 if (congestionMarkTag != nullptr) {
146 lpPacket.add<lp::CongestionMarkField>(*congestionMarkTag);
Eric Newberry86d31872015-09-23 16:24:59 -0700147 }
Eric Newberry86d31872015-09-23 16:24:59 -0700148}
149
Eric Newberrya98bf932015-09-21 00:58:47 -0700150void
Eric Newberry41aba102017-11-01 16:42:13 -0700151GenericLinkService::sendNetPacket(lp::Packet&& pkt, bool isInterest)
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700152{
153 std::vector<lp::Packet> frags;
Eric Newberry7b0071e2017-07-03 17:33:31 +0000154 ssize_t mtu = this->getTransport()->getMtu();
155
156 // Make space for feature fields in fragments
157 if (m_options.reliabilityOptions.isEnabled && mtu != MTU_UNLIMITED) {
158 mtu -= LpReliability::RESERVED_HEADER_SPACE;
Eric Newberry7b0071e2017-07-03 17:33:31 +0000159 }
160
Eric Newberryb49313d2017-12-24 20:22:27 -0700161 if (m_options.allowCongestionMarking && mtu != MTU_UNLIMITED) {
162 mtu -= CONGESTION_MARK_SIZE;
163 }
164
165 BOOST_ASSERT(mtu == MTU_UNLIMITED || mtu > 0);
166
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700167 if (m_options.allowFragmentation && mtu != MTU_UNLIMITED) {
168 bool isOk = false;
169 std::tie(isOk, frags) = m_fragmenter.fragmentPacket(pkt, mtu);
170 if (!isOk) {
171 // fragmentation failed (warning is logged by LpFragmenter)
Junxiao Shi0de23a22015-12-03 20:07:02 +0000172 ++this->nFragmentationErrors;
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700173 return;
174 }
175 }
176 else {
Eric Newberry41aba102017-11-01 16:42:13 -0700177 if (m_options.reliabilityOptions.isEnabled) {
178 frags.push_back(pkt);
179 }
180 else {
181 frags.push_back(std::move(pkt));
182 }
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700183 }
184
Eric Newberry185ab292017-03-28 06:45:39 +0000185 if (frags.size() == 1) {
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700186 // even if indexed fragmentation is enabled, the fragmenter should not
187 // fragment the packet if it can fit in MTU
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700188 BOOST_ASSERT(!frags.front().has<lp::FragIndexField>());
189 BOOST_ASSERT(!frags.front().has<lp::FragCountField>());
190 }
191
Eric Newberry7b0071e2017-07-03 17:33:31 +0000192 // Only assign sequences to fragments if packet contains more than 1 fragment
193 if (frags.size() > 1) {
Eric Newberry185ab292017-03-28 06:45:39 +0000194 // Assign sequences to all fragments
195 this->assignSequences(frags);
196 }
197
198 if (m_options.reliabilityOptions.isEnabled && frags.front().has<lp::FragmentField>()) {
Eric Newberry41aba102017-11-01 16:42:13 -0700199 m_reliability.handleOutgoing(frags, std::move(pkt), isInterest);
Eric Newberry185ab292017-03-28 06:45:39 +0000200 }
201
202 for (lp::Packet& frag : frags) {
203 this->sendLpPacket(std::move(frag));
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700204 }
205}
206
207void
208GenericLinkService::assignSequence(lp::Packet& pkt)
209{
210 pkt.set<lp::SequenceField>(++m_lastSeqNo);
211}
212
213void
214GenericLinkService::assignSequences(std::vector<lp::Packet>& pkts)
215{
216 std::for_each(pkts.begin(), pkts.end(), bind(&GenericLinkService::assignSequence, this, _1));
217}
218
219void
Eric Newberryb49313d2017-12-24 20:22:27 -0700220GenericLinkService::checkCongestionLevel(lp::Packet& pkt)
221{
222 ssize_t sendQueueLength = getTransport()->getSendQueueLength();
223 // This operation requires that the transport supports retrieving current send queue length
224 if (sendQueueLength < 0) {
225 return;
226 }
227
228 // To avoid overflowing the queue, set the congestion threshold to at least half of the send
229 // queue capacity.
230 size_t congestionThreshold = m_options.defaultCongestionThreshold;
231 if (getTransport()->getSendQueueCapacity() >= 0) {
232 congestionThreshold = std::min(congestionThreshold,
233 static_cast<size_t>(getTransport()->getSendQueueCapacity()) /
234 DEFAULT_CONGESTION_THRESHOLD_DIVISOR);
235 }
236
237 if (sendQueueLength > 0) {
238 NFD_LOG_FACE_TRACE("txqlen=" << sendQueueLength << " threshold=" << congestionThreshold <<
239 " capacity=" << getTransport()->getSendQueueCapacity());
240 }
241
242 if (static_cast<size_t>(sendQueueLength) > congestionThreshold) { // Send queue is congested
243 const auto now = time::steady_clock::now();
244 if (now >= m_nextMarkTime || now >= m_lastMarkTime + m_options.baseCongestionMarkingInterval) {
245 // Mark at most one initial packet per baseCongestionMarkingInterval
246 if (m_nMarkedSinceInMarkingState == 0) {
247 m_nextMarkTime = now;
248 }
249
250 // Time to mark packet
251 pkt.set<lp::CongestionMarkField>(1);
252 ++nCongestionMarked;
253 NFD_LOG_FACE_DEBUG("LpPacket was marked as congested");
254
255 ++m_nMarkedSinceInMarkingState;
256 // Decrease the marking interval by the inverse of the square root of the number of packets
257 // marked in this incident of congestion
258 m_nextMarkTime += time::nanoseconds(static_cast<time::nanoseconds::rep>(
259 m_options.baseCongestionMarkingInterval.count() /
260 std::sqrt(m_nMarkedSinceInMarkingState)));
261 m_lastMarkTime = now;
262 }
263 }
264 else if (m_nextMarkTime != time::steady_clock::TimePoint::max()) {
265 // Congestion incident has ended, so reset
266 NFD_LOG_FACE_DEBUG("Send queue length dropped below congestion threshold");
267 m_nextMarkTime = time::steady_clock::TimePoint::max();
268 m_nMarkedSinceInMarkingState = 0;
269 }
270}
271
272void
Eric Newberrya98bf932015-09-21 00:58:47 -0700273GenericLinkService::doReceivePacket(Transport::Packet&& packet)
274{
Eric Newberry86d31872015-09-23 16:24:59 -0700275 try {
Eric Newberrya1939ba2015-10-09 12:35:03 -0700276 lp::Packet pkt(packet.packet);
277
Eric Newberry185ab292017-03-28 06:45:39 +0000278 if (m_options.reliabilityOptions.isEnabled) {
279 m_reliability.processIncomingPacket(pkt);
280 }
281
Eric Newberrya1939ba2015-10-09 12:35:03 -0700282 if (!pkt.has<lp::FragmentField>()) {
283 NFD_LOG_FACE_TRACE("received IDLE packet: DROP");
284 return;
285 }
286
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700287 if ((pkt.has<lp::FragIndexField>() || pkt.has<lp::FragCountField>()) &&
288 !m_options.allowReassembly) {
289 NFD_LOG_FACE_WARN("received fragment, but reassembly disabled: DROP");
Eric Newberrya1939ba2015-10-09 12:35:03 -0700290 return;
291 }
292
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700293 bool isReassembled = false;
294 Block netPkt;
295 lp::Packet firstPkt;
296 std::tie(isReassembled, netPkt, firstPkt) = m_reassembler.receiveFragment(packet.remoteEndpoint,
297 pkt);
298 if (isReassembled) {
299 this->decodeNetPacket(netPkt, firstPkt);
300 }
301 }
302 catch (const tlv::Error& e) {
303 ++this->nInLpInvalid;
304 NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
305 }
306}
Eric Newberry86d31872015-09-23 16:24:59 -0700307
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700308void
309GenericLinkService::decodeNetPacket(const Block& netPkt, const lp::Packet& firstPkt)
310{
311 try {
Eric Newberry86d31872015-09-23 16:24:59 -0700312 switch (netPkt.type()) {
313 case tlv::Interest:
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700314 if (firstPkt.has<lp::NackField>()) {
315 this->decodeNack(netPkt, firstPkt);
Eric Newberry86d31872015-09-23 16:24:59 -0700316 }
317 else {
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700318 this->decodeInterest(netPkt, firstPkt);
Eric Newberry86d31872015-09-23 16:24:59 -0700319 }
320 break;
321 case tlv::Data:
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700322 this->decodeData(netPkt, firstPkt);
Eric Newberry86d31872015-09-23 16:24:59 -0700323 break;
324 default:
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700325 ++this->nInNetInvalid;
Eric Newberry86d31872015-09-23 16:24:59 -0700326 NFD_LOG_FACE_WARN("unrecognized network-layer packet TLV-TYPE " << netPkt.type() << ": DROP");
327 return;
Eric Newberrya98bf932015-09-21 00:58:47 -0700328 }
329 }
Eric Newberry86d31872015-09-23 16:24:59 -0700330 catch (const tlv::Error& e) {
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700331 ++this->nInNetInvalid;
Eric Newberry86d31872015-09-23 16:24:59 -0700332 NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
333 }
334}
335
Eric Newberry86d31872015-09-23 16:24:59 -0700336void
337GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstPkt)
338{
339 BOOST_ASSERT(netPkt.type() == tlv::Interest);
340 BOOST_ASSERT(!firstPkt.has<lp::NackField>());
341
342 // forwarding expects Interest to be created with make_shared
343 auto interest = make_shared<Interest>(netPkt);
344
345 if (firstPkt.has<lp::NextHopFaceIdField>()) {
346 if (m_options.allowLocalFields) {
Junxiao Shi0de23a22015-12-03 20:07:02 +0000347 interest->setTag(make_shared<lp::NextHopFaceIdTag>(firstPkt.get<lp::NextHopFaceIdField>()));
Eric Newberry86d31872015-09-23 16:24:59 -0700348 }
349 else {
350 NFD_LOG_FACE_WARN("received NextHopFaceId, but local fields disabled: DROP");
351 return;
352 }
353 }
354
355 if (firstPkt.has<lp::CachePolicyField>()) {
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700356 ++this->nInNetInvalid;
Eric Newberry86d31872015-09-23 16:24:59 -0700357 NFD_LOG_FACE_WARN("received CachePolicy with Interest: DROP");
358 return;
359 }
360
361 if (firstPkt.has<lp::IncomingFaceIdField>()) {
362 NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
363 }
364
Eric Newberryee400b52016-11-24 14:12:48 +0000365 if (firstPkt.has<lp::CongestionMarkField>()) {
366 interest->setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
367 }
368
Eric Newberry86d31872015-09-23 16:24:59 -0700369 this->receiveInterest(*interest);
370}
371
372void
373GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt)
374{
375 BOOST_ASSERT(netPkt.type() == tlv::Data);
376
377 // forwarding expects Data to be created with make_shared
378 auto data = make_shared<Data>(netPkt);
379
380 if (firstPkt.has<lp::NackField>()) {
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700381 ++this->nInNetInvalid;
Eric Newberry86d31872015-09-23 16:24:59 -0700382 NFD_LOG_FACE_WARN("received Nack with Data: DROP");
383 return;
384 }
385
386 if (firstPkt.has<lp::NextHopFaceIdField>()) {
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700387 ++this->nInNetInvalid;
Eric Newberry86d31872015-09-23 16:24:59 -0700388 NFD_LOG_FACE_WARN("received NextHopFaceId with Data: DROP");
389 return;
390 }
391
392 if (firstPkt.has<lp::CachePolicyField>()) {
Junxiao Shi6eb02712017-05-27 22:48:02 +0000393 // CachePolicy is unprivileged and does not require allowLocalFields option.
394 // In case of an invalid CachePolicyType, get<lp::CachePolicyField> will throw,
395 // so it's unnecessary to check here.
396 data->setTag(make_shared<lp::CachePolicyTag>(firstPkt.get<lp::CachePolicyField>()));
Eric Newberry86d31872015-09-23 16:24:59 -0700397 }
398
399 if (firstPkt.has<lp::IncomingFaceIdField>()) {
400 NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
401 }
402
Eric Newberryee400b52016-11-24 14:12:48 +0000403 if (firstPkt.has<lp::CongestionMarkField>()) {
404 data->setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
405 }
406
Eric Newberry86d31872015-09-23 16:24:59 -0700407 this->receiveData(*data);
408}
409
410void
411GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt)
412{
413 BOOST_ASSERT(netPkt.type() == tlv::Interest);
414 BOOST_ASSERT(firstPkt.has<lp::NackField>());
415
416 lp::Nack nack((Interest(netPkt)));
417 nack.setHeader(firstPkt.get<lp::NackField>());
418
419 if (firstPkt.has<lp::NextHopFaceIdField>()) {
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700420 ++this->nInNetInvalid;
Eric Newberry86d31872015-09-23 16:24:59 -0700421 NFD_LOG_FACE_WARN("received NextHopFaceId with Nack: DROP");
422 return;
423 }
424
425 if (firstPkt.has<lp::CachePolicyField>()) {
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700426 ++this->nInNetInvalid;
Eric Newberry86d31872015-09-23 16:24:59 -0700427 NFD_LOG_FACE_WARN("received CachePolicy with Nack: DROP");
428 return;
429 }
430
431 if (firstPkt.has<lp::IncomingFaceIdField>()) {
432 NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
433 }
434
Eric Newberryee400b52016-11-24 14:12:48 +0000435 if (firstPkt.has<lp::CongestionMarkField>()) {
436 nack.setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
437 }
438
Eric Newberry86d31872015-09-23 16:24:59 -0700439 this->receiveNack(nack);
Eric Newberrya98bf932015-09-21 00:58:47 -0700440}
441
442} // namespace face
443} // namespace nfd