blob: d6d6c025b472c343e1358ef059f7bca11aea6a16 [file] [log] [blame]
Eric Newberrya98bf932015-09-21 00:58:47 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2015, 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
28namespace nfd {
29namespace face {
30
31NFD_LOG_INIT("GenericLinkService");
32
Eric Newberry4c3e6b82015-11-10 16:48:42 -070033GenericLinkServiceCounters::GenericLinkServiceCounters(const LpReassembler& reassembler)
34 : nReassembling(reassembler)
35{
36}
37
Eric Newberry86d31872015-09-23 16:24:59 -070038GenericLinkService::Options::Options()
39 : allowLocalFields(false)
Eric Newberry4c3e6b82015-11-10 16:48:42 -070040 , allowFragmentation(false)
41 , allowReassembly(false)
Eric Newberry86d31872015-09-23 16:24:59 -070042{
43}
44
45GenericLinkService::GenericLinkService(const GenericLinkService::Options& options)
Eric Newberry4c3e6b82015-11-10 16:48:42 -070046 : GenericLinkServiceCounters(m_reassembler)
47 , m_options(options)
48 , m_fragmenter(m_options.fragmenterOptions, this)
49 , m_reassembler(m_options.reassemblerOptions, this)
50 , m_lastSeqNo(-2)
Eric Newberry86d31872015-09-23 16:24:59 -070051{
Eric Newberry4c3e6b82015-11-10 16:48:42 -070052 m_reassembler.beforeTimeout.connect(bind([this] { ++nReassemblyTimeouts; }));
Eric Newberry86d31872015-09-23 16:24:59 -070053}
54
Eric Newberrya98bf932015-09-21 00:58:47 -070055void
56GenericLinkService::doSendInterest(const Interest& interest)
57{
58 lp::Packet lpPacket(interest.wireEncode());
Eric Newberry86d31872015-09-23 16:24:59 -070059 if (m_options.allowLocalFields) {
60 encodeLocalFields(interest, lpPacket);
61 }
Eric Newberry4c3e6b82015-11-10 16:48:42 -070062
63 sendNetPacket(std::move(lpPacket));
Eric Newberrya98bf932015-09-21 00:58:47 -070064}
65
66void
67GenericLinkService::doSendData(const Data& data)
68{
69 lp::Packet lpPacket(data.wireEncode());
Eric Newberry86d31872015-09-23 16:24:59 -070070 if (m_options.allowLocalFields) {
71 encodeLocalFields(data, lpPacket);
72 }
Eric Newberry4c3e6b82015-11-10 16:48:42 -070073
74 sendNetPacket(std::move(lpPacket));
Eric Newberrya98bf932015-09-21 00:58:47 -070075}
76
77void
78GenericLinkService::doSendNack(const lp::Nack& nack)
79{
80 lp::Packet lpPacket(nack.getInterest().wireEncode());
81 lpPacket.add<lp::NackField>(nack.getHeader());
Eric Newberry86d31872015-09-23 16:24:59 -070082 if (m_options.allowLocalFields) {
83 encodeLocalFields(nack.getInterest(), lpPacket);
84 }
Eric Newberry4c3e6b82015-11-10 16:48:42 -070085
86 sendNetPacket(std::move(lpPacket));
Eric Newberrya98bf932015-09-21 00:58:47 -070087}
88
Eric Newberry86d31872015-09-23 16:24:59 -070089bool
90GenericLinkService::encodeLocalFields(const Interest& interest, lp::Packet& lpPacket)
91{
92 if (interest.getLocalControlHeader().hasIncomingFaceId()) {
93 lpPacket.add<lp::IncomingFaceIdField>(interest.getIncomingFaceId());
94 }
95
96 if (interest.getLocalControlHeader().hasCachingPolicy()) {
97 // Packet must be dropped
98 return false;
99 }
100
101 return true;
102}
103
104bool
105GenericLinkService::encodeLocalFields(const Data& data, lp::Packet& lpPacket)
106{
107 if (data.getLocalControlHeader().hasIncomingFaceId()) {
108 lpPacket.add<lp::IncomingFaceIdField>(data.getIncomingFaceId());
109 }
110
111 if (data.getLocalControlHeader().hasCachingPolicy()) {
112 switch (data.getCachingPolicy()) {
113 case ndn::nfd::LocalControlHeader::CachingPolicy::NO_CACHE: {
114 lp::CachePolicy cachePolicy;
115 cachePolicy.setPolicy(lp::CachePolicyType::NO_CACHE);
116 lpPacket.add<lp::CachePolicyField>(cachePolicy);
117 break;
118 }
119 default: {
120 break;
121 }
122 }
123 }
124
125 return true;
126}
127
Eric Newberrya98bf932015-09-21 00:58:47 -0700128void
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700129GenericLinkService::sendNetPacket(lp::Packet&& pkt)
130{
131 std::vector<lp::Packet> frags;
132 const ssize_t mtu = this->getTransport()->getMtu();
133 if (m_options.allowFragmentation && mtu != MTU_UNLIMITED) {
134 bool isOk = false;
135 std::tie(isOk, frags) = m_fragmenter.fragmentPacket(pkt, mtu);
136 if (!isOk) {
137 // fragmentation failed (warning is logged by LpFragmenter)
138 ++nFragmentationErrors;
139 return;
140 }
141 }
142 else {
143 frags.push_back(pkt);
144 }
145
146 if (frags.size() > 1) {
147 // sequence is needed only if packet is fragmented
148 assignSequences(frags);
149 }
150 else {
151 // even if indexed fragmentation is enabled, the fragmenter should not
152 // fragment the packet if it can fit in MTU
153 BOOST_ASSERT(frags.size() > 0);
154 BOOST_ASSERT(!frags.front().has<lp::FragIndexField>());
155 BOOST_ASSERT(!frags.front().has<lp::FragCountField>());
156 }
157
158 for (const lp::Packet& frag : frags) {
159 Transport::Packet tp(frag.wireEncode());
160 if (mtu != MTU_UNLIMITED && tp.packet.size() > static_cast<size_t>(mtu)) {
161 ++nOutOverMtu;
162 NFD_LOG_FACE_WARN("attempt to send packet over MTU limit");
163 continue;
164 }
165 sendPacket(std::move(tp));
166 }
167}
168
169void
170GenericLinkService::assignSequence(lp::Packet& pkt)
171{
172 pkt.set<lp::SequenceField>(++m_lastSeqNo);
173}
174
175void
176GenericLinkService::assignSequences(std::vector<lp::Packet>& pkts)
177{
178 std::for_each(pkts.begin(), pkts.end(), bind(&GenericLinkService::assignSequence, this, _1));
179}
180
181void
Eric Newberrya98bf932015-09-21 00:58:47 -0700182GenericLinkService::doReceivePacket(Transport::Packet&& packet)
183{
Eric Newberry86d31872015-09-23 16:24:59 -0700184 try {
Eric Newberrya1939ba2015-10-09 12:35:03 -0700185 lp::Packet pkt(packet.packet);
186
187 if (!pkt.has<lp::FragmentField>()) {
188 NFD_LOG_FACE_TRACE("received IDLE packet: DROP");
189 return;
190 }
191
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700192 if ((pkt.has<lp::FragIndexField>() || pkt.has<lp::FragCountField>()) &&
193 !m_options.allowReassembly) {
194 NFD_LOG_FACE_WARN("received fragment, but reassembly disabled: DROP");
Eric Newberrya1939ba2015-10-09 12:35:03 -0700195 return;
196 }
197
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700198 bool isReassembled = false;
199 Block netPkt;
200 lp::Packet firstPkt;
201 std::tie(isReassembled, netPkt, firstPkt) = m_reassembler.receiveFragment(packet.remoteEndpoint,
202 pkt);
203 if (isReassembled) {
204 this->decodeNetPacket(netPkt, firstPkt);
205 }
206 }
207 catch (const tlv::Error& e) {
208 ++this->nInLpInvalid;
209 NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
210 }
211}
Eric Newberry86d31872015-09-23 16:24:59 -0700212
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700213void
214GenericLinkService::decodeNetPacket(const Block& netPkt, const lp::Packet& firstPkt)
215{
216 try {
Eric Newberry86d31872015-09-23 16:24:59 -0700217 switch (netPkt.type()) {
218 case tlv::Interest:
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700219 if (firstPkt.has<lp::NackField>()) {
220 this->decodeNack(netPkt, firstPkt);
Eric Newberry86d31872015-09-23 16:24:59 -0700221 }
222 else {
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700223 this->decodeInterest(netPkt, firstPkt);
Eric Newberry86d31872015-09-23 16:24:59 -0700224 }
225 break;
226 case tlv::Data:
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700227 this->decodeData(netPkt, firstPkt);
Eric Newberry86d31872015-09-23 16:24:59 -0700228 break;
229 default:
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700230 ++this->nInNetInvalid;
Eric Newberry86d31872015-09-23 16:24:59 -0700231 NFD_LOG_FACE_WARN("unrecognized network-layer packet TLV-TYPE " << netPkt.type() << ": DROP");
232 return;
Eric Newberrya98bf932015-09-21 00:58:47 -0700233 }
234 }
Eric Newberry86d31872015-09-23 16:24:59 -0700235 catch (const tlv::Error& e) {
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700236 ++this->nInNetInvalid;
Eric Newberry86d31872015-09-23 16:24:59 -0700237 NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
238 }
239}
240
Eric Newberry86d31872015-09-23 16:24:59 -0700241void
242GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstPkt)
243{
244 BOOST_ASSERT(netPkt.type() == tlv::Interest);
245 BOOST_ASSERT(!firstPkt.has<lp::NackField>());
246
247 // forwarding expects Interest to be created with make_shared
248 auto interest = make_shared<Interest>(netPkt);
249
250 if (firstPkt.has<lp::NextHopFaceIdField>()) {
251 if (m_options.allowLocalFields) {
252 interest->setNextHopFaceId(firstPkt.get<lp::NextHopFaceIdField>());
253 }
254 else {
255 NFD_LOG_FACE_WARN("received NextHopFaceId, but local fields disabled: DROP");
256 return;
257 }
258 }
259
260 if (firstPkt.has<lp::CachePolicyField>()) {
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700261 ++this->nInNetInvalid;
Eric Newberry86d31872015-09-23 16:24:59 -0700262 NFD_LOG_FACE_WARN("received CachePolicy with Interest: DROP");
263 return;
264 }
265
266 if (firstPkt.has<lp::IncomingFaceIdField>()) {
267 NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
268 }
269
270 this->receiveInterest(*interest);
271}
272
273void
274GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt)
275{
276 BOOST_ASSERT(netPkt.type() == tlv::Data);
277
278 // forwarding expects Data to be created with make_shared
279 auto data = make_shared<Data>(netPkt);
280
281 if (firstPkt.has<lp::NackField>()) {
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700282 ++this->nInNetInvalid;
Eric Newberry86d31872015-09-23 16:24:59 -0700283 NFD_LOG_FACE_WARN("received Nack with Data: DROP");
284 return;
285 }
286
287 if (firstPkt.has<lp::NextHopFaceIdField>()) {
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700288 ++this->nInNetInvalid;
Eric Newberry86d31872015-09-23 16:24:59 -0700289 NFD_LOG_FACE_WARN("received NextHopFaceId with Data: DROP");
290 return;
291 }
292
293 if (firstPkt.has<lp::CachePolicyField>()) {
294 if (m_options.allowLocalFields) {
295 lp::CachePolicyType policy = firstPkt.get<lp::CachePolicyField>().getPolicy();
296 switch (policy) {
297 case lp::CachePolicyType::NO_CACHE:
298 data->setCachingPolicy(ndn::nfd::LocalControlHeader::CachingPolicy::NO_CACHE);
299 break;
300 default:
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700301 ++this->nInNetInvalid;
Eric Newberry86d31872015-09-23 16:24:59 -0700302 NFD_LOG_FACE_WARN("unrecognized CachePolicyType " << policy << ": DROP");
303 return;
304 }
305 }
306 else {
307 NFD_LOG_FACE_WARN("received CachePolicy, but local fields disabled: IGNORE");
308 }
309 }
310
311 if (firstPkt.has<lp::IncomingFaceIdField>()) {
312 NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
313 }
314
315 this->receiveData(*data);
316}
317
318void
319GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt)
320{
321 BOOST_ASSERT(netPkt.type() == tlv::Interest);
322 BOOST_ASSERT(firstPkt.has<lp::NackField>());
323
324 lp::Nack nack((Interest(netPkt)));
325 nack.setHeader(firstPkt.get<lp::NackField>());
326
327 if (firstPkt.has<lp::NextHopFaceIdField>()) {
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700328 ++this->nInNetInvalid;
Eric Newberry86d31872015-09-23 16:24:59 -0700329 NFD_LOG_FACE_WARN("received NextHopFaceId with Nack: DROP");
330 return;
331 }
332
333 if (firstPkt.has<lp::CachePolicyField>()) {
Eric Newberry4c3e6b82015-11-10 16:48:42 -0700334 ++this->nInNetInvalid;
Eric Newberry86d31872015-09-23 16:24:59 -0700335 NFD_LOG_FACE_WARN("received CachePolicy with Nack: DROP");
336 return;
337 }
338
339 if (firstPkt.has<lp::IncomingFaceIdField>()) {
340 NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
341 }
342
343 this->receiveNack(nack);
Eric Newberrya98bf932015-09-21 00:58:47 -0700344}
345
346} // namespace face
347} // namespace nfd