blob: 9cdfa4d643e9ba0b7c1ff5e8279ffb84023eaefe [file] [log] [blame]
Alexander Afanasyeve3d126f2012-07-16 17:07:31 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2011 University of California, Los Angeles
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
19 * Ilya Moiseenko <iliamo@cs.ucla.edu>
20 */
21
22#include "ccnx-forwarding-strategy.h"
23
24#include "ns3/ccnx-pit.h"
25#include "ns3/ccnx-pit-entry.h"
26#include "ns3/ccnx-interest-header.h"
27#include "ns3/ccnx-content-object-header.h"
28#include "ns3/ccnx-pit.h"
29#include "ns3/ccnx-fib.h"
30#include "ns3/ccnx-content-store.h"
31
32#include "ns3/assert.h"
33#include "ns3/ptr.h"
34#include "ns3/log.h"
35#include "ns3/simulator.h"
36#include "ns3/boolean.h"
37#include "ns3/string.h"
38
39#include <boost/ref.hpp>
40#include <boost/foreach.hpp>
41#include <boost/lambda/lambda.hpp>
42#include <boost/lambda/bind.hpp>
43#include <boost/tuple/tuple.hpp>
44namespace ll = boost::lambda;
45
46NS_LOG_COMPONENT_DEFINE ("CcnxForwardingStrategy");
47
48namespace ns3 {
49
50using namespace __ccnx_private;
51
52NS_OBJECT_ENSURE_REGISTERED (CcnxForwardingStrategy);
53
54TypeId CcnxForwardingStrategy::GetTypeId (void)
55{
56 static TypeId tid = TypeId ("ns3::CcnxForwardingStrategy")
57 .SetGroupName ("Ccnx")
58 .SetParent<Object> ()
59
60 ////////////////////////////////////////////////////////////////////
61 ////////////////////////////////////////////////////////////////////
62
63 .AddTraceSource ("OutInterests", "OutInterests", MakeTraceSourceAccessor (&CcnxForwardingStrategy::m_outInterests))
64 .AddTraceSource ("InInterests", "InInterests", MakeTraceSourceAccessor (&CcnxForwardingStrategy::m_inInterests))
65 .AddTraceSource ("DropInterests", "DropInterests", MakeTraceSourceAccessor (&CcnxForwardingStrategy::m_dropInterests))
66
67 ////////////////////////////////////////////////////////////////////
68 ////////////////////////////////////////////////////////////////////
69
70 .AddTraceSource ("OutNacks", "OutNacks", MakeTraceSourceAccessor (&CcnxForwardingStrategy::m_outNacks))
71 .AddTraceSource ("InNacks", "InNacks", MakeTraceSourceAccessor (&CcnxForwardingStrategy::m_inNacks))
72 .AddTraceSource ("DropNacks", "DropNacks", MakeTraceSourceAccessor (&CcnxForwardingStrategy::m_dropNacks))
73
74 ////////////////////////////////////////////////////////////////////
75 ////////////////////////////////////////////////////////////////////
76
77 .AddTraceSource ("OutData", "OutData", MakeTraceSourceAccessor (&CcnxForwardingStrategy::m_outData))
78 .AddTraceSource ("InData", "InData", MakeTraceSourceAccessor (&CcnxForwardingStrategy::m_inData))
79 .AddTraceSource ("DropData", "DropData", MakeTraceSourceAccessor (&CcnxForwardingStrategy::m_dropData))
80
81 .AddAttribute ("EnableNACKs", "Enabling support of NACKs",
82 BooleanValue (false),
83 MakeBooleanAccessor (&CcnxForwardingStrategy::m_nacksEnabled),
84 MakeBooleanChecker ())
85 .AddAttribute ("CacheUnsolicitedData", "Cache overheard data that have not been requested",
86 BooleanValue (false),
87 MakeBooleanAccessor (&CcnxForwardingStrategy::m_cacheUnsolicitedData),
88 MakeBooleanChecker ())
89
90 ;
91 return tid;
92}
93
94CcnxForwardingStrategy::CcnxForwardingStrategy ()
95{
96}
97
98CcnxForwardingStrategy::~CcnxForwardingStrategy ()
99{
100}
101
102void
103CcnxForwardingStrategy::NotifyNewAggregate ()
104{
105 if (m_pit == 0)
106 {
107 m_pit = GetObject<CcnxPit> ();
108 }
109 if (m_fib == 0)
110 {
111 m_fib = GetObject<CcnxFib> ();
112 }
113 if (m_contentStore == 0)
114 {
115 m_contentStore = GetObject<CcnxContentStore> ();
116 }
117
118 Object::NotifyNewAggregate ();
119}
120
121void
122CcnxForwardingStrategy::DoDispose ()
123{
124 m_pit = 0;
125 m_contentStore = 0;
126 m_fib = 0;
127
128 Object::DoDispose ();
129}
130
131void
132CcnxForwardingStrategy::OnInterest (const Ptr<CcnxFace> &incomingFace,
133 Ptr<CcnxInterestHeader> &header,
134 const Ptr<const Packet> &packet)
135{
136 m_inInterests (header, incomingFace);
137
138 Ptr<CcnxPitEntry> pitEntry = m_pit->Lookup (*header);
139 if (pitEntry == 0)
140 {
141 pitEntry = m_pit->Create (header);
142 }
143
144 if (pitEntry == 0)
145 {
146 // if it is still not created, then give up processing
147 m_dropInterests (header, incomingFace);
148 return;
149 }
150
151 bool isNew = pitEntry->GetIncoming ().size () == 0 && pitEntry->GetOutgoing ().size () == 0;
152 bool isDuplicated = true;
153 if (!pitEntry->IsNonceSeen (header->GetNonce ()))
154 {
155 pitEntry->AddSeenNonce (header->GetNonce ());
156 isDuplicated = false;
157 }
158
159 NS_LOG_FUNCTION (header->GetName () << header->GetNonce () << boost::cref (*incomingFace) << isDuplicated);
160
161 /////////////////////////////////////////////////////////////////////////////////////////
162 /////////////////////////////////////////////////////////////////////////////////////////
163 /////////////////////////////////////////////////////////////////////////////////////////
164 // //
165 // !!!! IMPORTANT CHANGE !!!! Duplicate interests will create incoming face entry !!!! //
166 // //
167 /////////////////////////////////////////////////////////////////////////////////////////
168 /////////////////////////////////////////////////////////////////////////////////////////
169 /////////////////////////////////////////////////////////////////////////////////////////
170
171 // Data is not in cache
172 CcnxPitEntry::in_iterator inFace = pitEntry->GetIncoming ().find (incomingFace);
173 CcnxPitEntry::out_iterator outFace = pitEntry->GetOutgoing ().find (incomingFace);
174
175 bool isRetransmitted = false;
176
177 if (inFace != pitEntry->GetIncoming ().end ())
178 {
179 // CcnxPitEntryIncomingFace.m_arrivalTime keeps track arrival time of the first packet... why?
180
181 isRetransmitted = true;
182 // this is almost definitely a retransmission. But should we trust the user on that?
183 }
184 else
185 {
186 inFace = pitEntry->AddIncoming (incomingFace);
187 }
188 //////////////////////////////////////////////////////////////////////////////////
189 //////////////////////////////////////////////////////////////////////////////////
190 //////////////////////////////////////////////////////////////////////////////////
191
192 if (isDuplicated)
193 {
194 NS_LOG_DEBUG ("Received duplicatie interest on " << *incomingFace);
195 m_dropInterests (header, incomingFace);
196
197 /**
198 * This condition will handle "routing" loops and also recently satisfied interests.
199 * Every time interest is satisfied, PIT entry (with empty incoming and outgoing faces)
200 * is kept for another small chunk of time.
201 */
202
203 if (m_nacksEnabled)
204 {
205 NS_LOG_DEBUG ("Sending NACK_LOOP");
206 header->SetNack (CcnxInterestHeader::NACK_LOOP);
207 Ptr<Packet> nack = Create<Packet> ();
208 nack->AddHeader (*header);
209
210 incomingFace->Send (nack);
211 m_outNacks (header, incomingFace);
212 }
213
214 return;
215 }
216
217 Ptr<Packet> contentObject;
218 Ptr<const CcnxContentObjectHeader> contentObjectHeader; // used for tracing
219 Ptr<const Packet> payload; // used for tracing
220 boost::tie (contentObject, contentObjectHeader, payload) = m_contentStore->Lookup (header);
221 if (contentObject != 0)
222 {
223 NS_ASSERT (contentObjectHeader != 0);
224 NS_LOG_LOGIC("Found in cache");
225
226 OnDataDelayed (contentObjectHeader, payload, contentObject);
227 return;
228 }
229
230 // update PIT entry lifetime
231 pitEntry->UpdateLifetime (header->GetInterestLifetime ());
232
233 if (outFace != pitEntry->GetOutgoing ().end ())
234 {
235 NS_LOG_DEBUG ("Non duplicate interests from the face we have sent interest to. Don't suppress");
236 // got a non-duplicate interest from the face we have sent interest to
237 // Probably, there is no point in waiting data from that face... Not sure yet
238
239 // If we're expecting data from the interface we got the interest from ("producer" asks us for "his own" data)
240 // Mark interface YELLOW, but keep a small hope that data will come eventually.
241
242 // ?? not sure if we need to do that ?? ...
243
244 pitEntry->GetFibEntry ()->UpdateStatus (incomingFace, CcnxFibFaceMetric::NDN_FIB_YELLOW);
245 // StaticCast<CcnxFibImpl> (m_fib)->modify(pitEntry->GetFibEntry (),
246 // ll::bind (&CcnxFibEntry::UpdateStatus,
247 // ll::_1, incomingFace, CcnxFibFaceMetric::NDN_FIB_YELLOW));
248 }
249 else
250 if (!isNew && !isRetransmitted)
251 {
252 // Suppress this interest if we're still expecting data from some other face
253 NS_LOG_DEBUG ("Suppress interests");
254 m_dropInterests (header, incomingFace);
255 return;
256 }
257
258 /////////////////////////////////////////////////////////////////////
259 // Propagate
260 /////////////////////////////////////////////////////////////////////
261
262 bool propagated = PropagateInterest (pitEntry, incomingFace, header, packet);
263
264 if (!propagated && isRetransmitted) //give another chance if retransmitted
265 {
266 // increase max number of allowed retransmissions
267 pitEntry->IncreaseAllowedRetxCount ();
268
269 // try again
270 propagated = PropagateInterest (pitEntry, incomingFace, header, packet);
271 }
272
273 // ForwardingStrategy will try its best to forward packet to at least one interface.
274 // If no interests was propagated, then there is not other option for forwarding or
275 // ForwardingStrategy failed to find it.
276 if (!propagated)
277 {
278 NS_LOG_DEBUG ("Not propagated");
279 m_dropInterests (header, incomingFace);
280 GiveUpInterest (pitEntry, header);
281 }
282}
283
284void
285CcnxForwardingStrategy::OnData (const Ptr<CcnxFace> &incomingFace,
286 Ptr<CcnxContentObjectHeader> &header,
287 Ptr<Packet> &payload,
288 const Ptr<const Packet> &packet)
289{
290 NS_LOG_FUNCTION (incomingFace << header->GetName () << payload << packet);
291 m_inData (header, payload, incomingFace);
292
293 // 1. Lookup PIT entry
294 Ptr<CcnxPitEntry> pitEntry = m_pit->Lookup (*header);
295 if (pitEntry != 0)
296 {
297 // Note that with MultiIndex we need to modify entries indirectly
298
299 CcnxPitEntry::out_iterator out = pitEntry->GetOutgoing ().find (incomingFace);
300
301 // If we have sent interest for this data via this face, then update stats.
302 if (out != pitEntry->GetOutgoing ().end ())
303 {
304 pitEntry->GetFibEntry ()->UpdateFaceRtt (incomingFace, Simulator::Now () - out->m_sendTime);
305 // StaticCast<CcnxFibImpl> (m_fib)->modify (pitEntry->GetFibEntry (),
306 // ll::bind (&CcnxFibEntry::UpdateFaceRtt,
307 // ll::_1,
308 // incomingFace,
309 // Simulator::Now () - out->m_sendTime));
310 }
311 else
312 {
313 // Unsolicited data, but we're interested in it... should we get it?
314 // Potential hole for attacks
315
316 if (m_cacheUnsolicitedData)
317 {
318 // Optimistically add or update entry in the content store
319 m_contentStore->Add (header, payload);
320 }
321 else
322 {
323 NS_LOG_ERROR ("PIT entry for "<< header->GetName ()<<" is valid, "
324 "but outgoing entry for interface "<< boost::cref(*incomingFace) <<" doesn't exist\n");
325 }
326 // ignore unsolicited data
327 return;
328 }
329
330 // Update metric status for the incoming interface in the corresponding FIB entry
331 pitEntry->GetFibEntry ()->UpdateStatus (incomingFace, CcnxFibFaceMetric::NDN_FIB_GREEN);
332 // StaticCast<CcnxFibImpl>(m_fib)->modify (pitEntry->GetFibEntry (),
333 // ll::bind (&CcnxFibEntry::UpdateStatus, ll::_1,
334 // incomingFace, CcnxFibFaceMetric::NDN_FIB_GREEN));
335
336 // Add or update entry in the content store
337 m_contentStore->Add (header, payload);
338
339 pitEntry->RemoveIncoming (incomingFace);
340
341 if (pitEntry->GetIncoming ().size () == 0)
342 {
343 // Set pruning timout on PIT entry (instead of deleting the record)
344 m_pit->MarkErased (pitEntry);
345 }
346 else
347 {
348 OnDataDelayed (header, payload, packet);
349 }
350 }
351 else
352 {
353 NS_LOG_DEBUG ("Pit entry not found");
354 if (m_cacheUnsolicitedData)
355 {
356 // Optimistically add or update entry in the content store
357 m_contentStore->Add (header, payload);
358 }
359 else
360 {
361 // Drop data packet if PIT entry is not found
362 // (unsolicited data packets should not "poison" content store)
363
364 //drop dulicated or not requested data packet
365 m_dropData (header, payload, incomingFace);
366 }
367 return; // do not process unsoliced data packets
368 }
369}
370
371
372bool
373CcnxForwardingStrategy::PropagateInterestViaGreen (Ptr<CcnxPitEntry> pitEntry,
374 const Ptr<CcnxFace> &incomingFace,
375 Ptr<CcnxInterestHeader> &header,
376 const Ptr<const Packet> &packet)
377{
378 NS_LOG_FUNCTION (this);
379 NS_ASSERT_MSG (m_pit != 0, "PIT should be aggregated with forwarding strategy");
380
381 int propagatedCount = 0;
382
383 BOOST_FOREACH (const CcnxFibFaceMetric &metricFace, pitEntry->GetFibEntry ()->m_faces.get<i_metric> ())
384 {
385 if (metricFace.m_status == CcnxFibFaceMetric::NDN_FIB_RED ||
386 metricFace.m_status == CcnxFibFaceMetric::NDN_FIB_YELLOW)
387 break; //propagate only to green faces
388
389 if (pitEntry->GetIncoming ().find (metricFace.m_face) != pitEntry->GetIncoming ().end ())
390 continue; // don't forward to face that we received interest from
391
392 CcnxPitEntryOutgoingFaceContainer::type::iterator outgoing =
393 pitEntry->GetOutgoing ().find (metricFace.m_face);
394
395 if (outgoing != pitEntry->GetOutgoing ().end () &&
396 outgoing->m_retxCount >= pitEntry->GetMaxRetxCount ())
397 {
398 NS_LOG_DEBUG ("retxCount: " << outgoing->m_retxCount << ", maxRetxCount: " << pitEntry->GetMaxRetxCount ());
399 continue;
400 }
401
402 bool faceAvailable = metricFace.m_face->IsBelowLimit ();
403 if (!faceAvailable) // huh...
404 {
405 // let's try different green face
406 continue;
407 }
408
409 pitEntry->AddOutgoing (metricFace.m_face);
410
411 Ptr<Packet> packetToSend = packet->Copy ();
412
413 //transmission
414 metricFace.m_face->Send (packetToSend);
415 m_outInterests (header, metricFace.m_face);
416
417 propagatedCount++;
418 break; // propagate only one interest
419 }
420
421 return propagatedCount > 0;
422}
423
424void
425CcnxForwardingStrategy::OnDataDelayed (Ptr<const CcnxContentObjectHeader> header,
426 Ptr<const Packet> payload,
427 const Ptr<const Packet> &packet)
428{
429 // 1. Lookup PIT entry
430 Ptr<CcnxPitEntry> pitEntry = m_pit->Lookup (*header);
431 if (pitEntry != 0)
432 {
433 //satisfy all pending incoming Interests
434 BOOST_FOREACH (const CcnxPitEntryIncomingFace &incoming, pitEntry->GetIncoming ())
435 {
436 incoming.m_face->Send (packet->Copy ());
437 m_outData (header, payload, false, incoming.m_face);
438 NS_LOG_DEBUG ("Satisfy " << *incoming.m_face);
439
440 // successfull forwarded data trace
441 }
442
443 if (pitEntry->GetIncoming ().size () > 0)
444 {
445 // All incoming interests are satisfied. Remove them
446 pitEntry->ClearIncoming ();
447
448 // Remove all outgoing faces
449 pitEntry->ClearOutgoing ();
450
451 // Set pruning timout on PIT entry (instead of deleting the record)
452 m_pit->MarkErased (pitEntry);
453 }
454 }
455 else
456 {
457 NS_LOG_DEBUG ("Pit entry not found (was satisfied and removed before)");
458 return; // do not process unsoliced data packets
459 }
460}
461
462void
463CcnxForwardingStrategy::GiveUpInterest (Ptr<CcnxPitEntry> pitEntry,
464 Ptr<CcnxInterestHeader> header)
465{
466 NS_LOG_FUNCTION (this);
467
468 if (m_nacksEnabled)
469 {
470 Ptr<Packet> packet = Create<Packet> ();
471 header->SetNack (CcnxInterestHeader::NACK_GIVEUP_PIT);
472 packet->AddHeader (*header);
473
474 BOOST_FOREACH (const CcnxPitEntryIncomingFace &incoming, pitEntry->GetIncoming ())
475 {
476 NS_LOG_DEBUG ("Send NACK for " << boost::cref (header->GetName ()) << " to " << boost::cref (*incoming.m_face));
477 incoming.m_face->Send (packet->Copy ());
478
479 m_outNacks (header, incoming.m_face);
480 }
481
482 // All incoming interests cannot be satisfied. Remove them
483 pitEntry->ClearIncoming ();
484
485 // Remove also outgoing
486 pitEntry->ClearOutgoing ();
487
488 // Set pruning timout on PIT entry (instead of deleting the record)
489 m_pit->MarkErased (pitEntry);
490 }
491}
492
493
494} //namespace ns3