NACK interests support and congestion detection
diff --git a/model/ccnx-l3-protocol.cc b/model/ccnx-l3-protocol.cc
index a4241bc..13bf2f0 100644
--- a/model/ccnx-l3-protocol.cc
+++ b/model/ccnx-l3-protocol.cc
@@ -16,6 +16,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ * Ilya Moiseenko <iliamo@cs.ucla.edu>
*/
#include "ccnx-l3-protocol.h"
@@ -265,60 +266,329 @@
const Ptr<const Packet> &packet)
{
NS_LOG_LOGIC ("Receiving interest from " << &incomingFace);
- m_receivedInterestsTrace (header, m_node->GetObject<Ccnx> ()/*this*/, incomingFace);
+ m_receivedInterestsTrace (header, m_node->GetObject<Ccnx> (), incomingFace);
+ // Lookup of Pit and Fib entries for this Interest
+ CcnxFibEntryContainer::type::iterator fibEntry;
+ CcnxPitEntryContainer::type::iterator pitEntry = m_pit->Lookup (*header, fibEntry);
+
+ // No matter is it duplicate or not, if it is a NACK message, remove all possible incoming
+ // entries for this interface (NACK means that neighbor gave up trying and there is no
+ // point of sending data in this direction)
+ if ((header->IsNack()) && (pitEntry != m_pit->end ()))
+ {
+ //m_pit->erase (pitEntry);
+ m_pit->modify(pitEntry, CcnxPitEntry::DeleteIncoming(incomingFace));
+ }
+
+
if (m_rit->WasRecentlySatisfied (*header))
{
+ // duplicate interests (same nonce) from applications are just ignored
+ if (incomingFace->IsLocal() == true)
+ return;
+
+ // Update metric status for the incoming interface in the corresponding FIB entry
+ if (fibEntry != m_fib->end())
+ m_fib->modify (m_fib->iterator_to (pitEntry->m_fibEntry),
+ CcnxFibEntry::UpdateStatus(incomingFace, CcnxFibFaceMetric::NDN_FIB_YELLOW));
+
+ //Trace duplicate interest
m_droppedInterestsTrace (header, NDN_DUPLICATE_INTEREST,
- m_node->GetObject<Ccnx> ()/*this*/, incomingFace);
+ m_node->GetObject<Ccnx> (), incomingFace);
+
+ bool isMine = false;
+ TypeId tid = TypeId ("ns3::CcnxProducer");
+ for(uint32_t i=0; i<m_node->GetNApplications();i++)
+ {
+ Ptr<Application> app = m_node->GetApplication(i);
+ if(app->GetTypeId() == tid)
+ {
+ if((DynamicCast<CcnxProducer>(app))->GetPrefix () == header->GetName ())
+ {
+ isMine = true;
+ break;
+ }
+ }
+ }
+
+ Ptr<Packet> contentObject = m_contentStore->Lookup (header);
+ if ((isMine == true) || (contentObject != NULL))
+ {
+ //never respond with NACK to NACK
+ if(header->IsNack () )
+ return;
+
+ // always return a duplicate packet
+ header->SetNack(true);
+ //Trace duplicate interest
+ m_droppedInterestsTrace (header, NDN_DUPLICATE_INTEREST,
+ m_node->GetObject<Ccnx> (), incomingFace);
+
+ SendInterest(incomingFace, header, packet->Copy());
+
+ return;
+ }
+
+
+ // check PIT. or there is no outgoing entry for this interface,
+ // silently drop the duplicate packet
+
+ // If no entry found, silently drop
+ if( pitEntry == m_pit->end() )
+ return;
+
+ // If PIT entry timed out, silently drop
+ if( pitEntry->m_timerExpired == true )
+ return;
+
// loop?
- return;
+
+ // Check if there is no outgoing entry for the interface or different nonce
+ // (i.e., got a duplicate packet, but we haven't sent interest to this
+ // interface)
+ //
+ // This case means that there is a loop in the network.
+ // So, prune this link, but do not remove PIT entry
+
+ // Alex, check this condition!!
+ if(pitEntry->m_outgoing.size () == 0)
+ {
+ //never respond with NACK to NACK
+ if(header->IsNack () )
+ return;
+
+ // always return a duplicate packet
+ header->SetNack(true);
+ //Trace duplicate interest
+ m_droppedInterestsTrace (header, NDN_DUPLICATE_INTEREST,
+ m_node->GetObject<Ccnx> (), incomingFace);
+
+ SendInterest(incomingFace, header, packet->Copy());
+ return;
+ }
+
+
+ // At this point:
+ // - there is a non-expired PIT entry,
+ // - there is an outgoing interest to the interface, and
+ // - a nonce in outgoing entry is equal to a nonce in the received duplicate packet
+
+ // Should perform:
+ // Cleaning outgoing entry
+ // If there are no outgoing interests and available interfaces left (pe->availableInterfaces),
+ // prune all incoming interests, otherwise allow forwarding of the interest
+ if( header->IsNack () )
+ {
+ if( header->IsCongested () == false )
+ m_pit->LeakBucket(incomingFace,1);
+
+ m_pit->modify(pitEntry, CcnxPitEntry::DeleteOutgoing(incomingFace));
+ }
+ else
+ {
+ //poit->waitingInVain = true;
+ }
+
+
+ // prune all incoming interests
+ if((pitEntry->m_outgoing.size() ==0) && (pitEntry->m_fibEntry.m_faces.size() == 0))
+ {
+ BOOST_FOREACH (const CcnxPitEntryIncomingFace face, pitEntry->m_incoming)
+ {
+ if(face.m_face->IsLocal() == false)
+ {
+ // check all entries if the name of RIT entry matches the name of interest
+ for (CcnxRitByNonce::type::iterator it = m_rit->begin(); it != m_rit->end(); it++)
+ {
+ if (it->m_prefix == pitEntry->GetPrefix() )
+ {
+
+ header->SetNonce(it->m_nonce);
+ header->SetNack(true);
+ SendInterest(face.m_face, header, packet->Copy());
+ break;
+ }
+ }
+ }
+ }
+
+ // Finally, remote the PIT entry
+ m_pit->erase (pitEntry);
+
+ return; // stop processing
+ }
+
+ if(pitEntry->m_fibEntry.m_faces.size() == 0)
+ return;
}
+
+ // Otherwise,
+ // propagate the interest
+ //
+ // method `propagateInterest' can/should try different interface
+ // from `availableInterfaces' list
+
m_rit->SetRecentlySatisfied (*header);
+ NS_LOG_INFO("Cache Lookup for " << header->GetName());
Ptr<Packet> contentObject = m_contentStore->Lookup (header);
- if (contentObject != 0)
+ if (contentObject != NULL)
{
+ NS_LOG_INFO("Found in cache");
+
TransmittedDataTrace (contentObject, CACHED,
- m_node->GetObject<Ccnx> ()/*this*/, incomingFace);
+ m_node->GetObject<Ccnx> (), incomingFace);
incomingFace->Send (contentObject);
return;
}
- CcnxPitEntry pitEntry = m_pit->Lookup (*header);
+ // Data is not in cache
- CcnxPitEntryIncomingFaceContainer::type::iterator inFace = pitEntry.m_incoming.find (incomingFace);
- CcnxPitEntryOutgoingFaceContainer::type::iterator outFace = pitEntry.m_outgoing.find (incomingFace);
+ CcnxPitEntryIncomingFaceContainer::type::iterator inFace = pitEntry->m_incoming.find (incomingFace);
+ CcnxPitEntryOutgoingFaceContainer::type::iterator outFace = pitEntry->m_outgoing.find (incomingFace);
+
+ if ((pitEntry != m_pit->end()) && (pitEntry->m_timerExpired == false))
+ {
+ //CcnxFibFaceMetricContainer::type m_faces;
+ //pitEntry->m_fibEntry->m_faces
+
+ // If we're expecting data from the interface we got the interest from ("producer" asks us for "his own" data)
+ // Give up this interface, but keep a small hope when the returned packet doesn't have PRUNE status
+ if( inFace->m_face == outFace->m_face )
+ {
+ if( header->IsCongested() == true )
+ {
+ m_pit->LeakBucket(incomingFace, 1);
+ m_pit->modify (pitEntry, CcnxPitEntry::DeleteOutgoing(outFace->m_face));
+ }
+ //else
+ // poit->waitingInVain = true;
+
+ // Update metric status for the incoming interface in the corresponding FIB entry
+ if(fibEntry != m_fib->end())
+ m_fib->modify(m_fib->iterator_to (pitEntry->m_fibEntry),
+ CcnxFibEntry::UpdateStatus(incomingFace, CcnxFibFaceMetric::NDN_FIB_YELLOW));
+ }
+ }
+
+
+ if((pitEntry->m_outgoing.size() == 0) && (pitEntry->m_fibEntry.m_faces.size() == 0))
+ // prune all incoming interests
+ {
+
+ for(CcnxPitEntryContainer::type::iterator iter = m_pit->begin();
+ iter != m_pit->end();
+ iter++)
+ {
+ /*for(CcnxPitEntryIncomingFaceContainer::type::iterator face = iter->m_incoming.begin();
+ face != iter->m_incoming.end();
+ face++)*/
+ BOOST_FOREACH (const CcnxPitEntryIncomingFace face, iter->m_incoming)
+ {
+ if(face.m_face->IsLocal() == true)
+ {
+ //returnInterestToApp( pkt, -piit->interfaceIndex );
+ //continue;
+ }
+
+ // check all entries if the name of RIT entry matches the name of interest
+ for (CcnxRitByNonce::type::iterator it = m_rit->begin(); it != m_rit->end(); it++)
+ {
+ if (it->m_prefix == iter->GetPrefix() )
+ {
+ header->SetNonce(it->m_nonce);
+ header->SetNack(true);
+ SendInterest(face.m_face, header, packet->Copy());
+ }
+ }
+ }
+
+ }
+
+ m_pit->erase(pitEntry);
+
+ return; // there is nothing else to do
+ }
+
+ // Suppress this interest only if we're still expecting data from some other interface
+ if( pitEntry->m_outgoing.size() > 0 )
+ {
+ return; //ok. Now we can suppress this interest
+ }
+
+
+ // Prune and delete PIT entry if there are no available interfaces to propagate interest
+ if( pitEntry->m_fibEntry.m_faces.size() == 0)
+ {
+ //if no match is found in the FIB, drop packet
+ //printf( "Node %d: cannot process Interest packet %s (no interfaces left)\n", _node->nodeId, pkt->contentName );
+
+ if(incomingFace->IsLocal() == false)
+ {
+ header->SetNack(true);
+ m_droppedInterestsTrace (header, NDN_SUPPRESSED_INTEREST,
+ m_node->GetObject<Ccnx> (), incomingFace);
+ SendInterest(incomingFace, header, packet->Copy());
+ }
+
+ m_pit->erase(pitEntry);
+
+ }
+
+
+
+ // otherwise, try one of the available interfaces
+
+ // suppress interest if
+ /*if (pitEntry->m_incoming.size () != 0 && // not a new PIT entry and
+ inFace != pitEntry->m_incoming.end ()) // existing entry, but interest received via different face
+ {
+ m_droppedInterestsTrace (header, NDN_SUPPRESSED_INTEREST,
+ m_node->GetObject<Ccnx> (), incomingFace);
+ return;
+ }*/
+
+
+ //just in case of bug
+ header->SetNack(false);
+ header->SetCongested(false);
- // // suppress interest if
- // if (pitEntry.m_incoming.size () != 0 && // not a new PIT entry and
- // inFace != pitEntry.m_incoming.end ()) // existing entry, but interest received via different face
- // {
- // m_droppedInterestsTrace (header, NDN_SUPPRESSED_INTEREST,
- // m_node->GetObject<Ccnx> ()/*this*/, incomingFace);
- // return;
- // }
+ NS_ASSERT_MSG (m_forwardingStrategy != 0, "Need a forwarding protocol object to process packets");
- NS_ASSERT_MSG (m_forwardingStrategy != 0, "Need a forwarding protocol object to process packets");
-
- /*bool propagated = */m_forwardingStrategy->
- PropagateInterest (incomingFace, header, packet,
+ m_pit->modify (pitEntry, CcnxPitEntry::AddIncoming(incomingFace));
+
+ bool propagated = m_forwardingStrategy->
+ PropagateInterest (pitEntry, fibEntry,incomingFace, header, packet,
MakeCallback (&CcnxL3Protocol::SendInterest, this)
);
- // // If interest wasn't propagated further (probably, a limit is reached),
- // // prune and delete PIT entry if there are no outstanding interests.
- // // Stop processing otherwise.
- // if( !propagated && pitEntry.numberOfPromisingInterests()==0 )
- // {
- // // printf( "Node %d. Pruning after unsuccessful try to forward an interest\n", _node->nodeId );
-
- // BOOST_FOREACH (const CcnxPitEntryIncomingFace face, pitEntry.m_incoming)
- // {
- // // send prune
- // }
- // m_pit->erase (m_pit->iterator_to (pitEntry));
- // }
+ // If interest wasn't propagated further (probably, a limit is reached),
+ // prune and delete PIT entry if there are no outstanding interests.
+ // Stop processing otherwise.
+ if( (!propagated) && (pitEntry->m_outgoing.size() == 0))
+ {
+ BOOST_FOREACH (const CcnxPitEntryIncomingFace face, pitEntry->m_incoming)
+ {
+
+
+ header->SetNack(true);
+ header->SetCongested(true);
+ SendInterest (face.m_face, header, packet->Copy());
+
+ m_droppedInterestsTrace (header, DROP_CONGESTION,
+ m_node->GetObject<Ccnx> (), incomingFace);
+ }
+
+ m_pit->erase (pitEntry);
+ }
+ /*}
+ else
+ {
+ m_droppedInterestsTrace (header, NDN_PIT_TIMER_EXPIRED,
+ m_node->GetObject<Ccnx> (), incomingFace);
+ return;
+ }*/
}
// Processing ContentObjects
@@ -327,7 +597,7 @@
Ptr<Packet> &payload,
const Ptr<const Packet> &packet)
{
-
+
NS_LOG_LOGIC ("Receiving contentObject from " << &incomingFace);
m_receivedDataTrace (header, payload, m_node->GetObject<Ccnx> ()/*this*/, incomingFace);
@@ -343,6 +613,7 @@
CcnxFibEntry::UpdateStatus (incomingFace, CcnxFibFaceMetric::NDN_FIB_GREEN));
// Add or update entry in the content store
+ NS_LOG_INFO("Cached " << header->GetName());
m_contentStore->Add (header, payload);
CcnxPitEntryOutgoingFaceContainer::type::iterator
@@ -435,4 +706,9 @@
}
}
+Ptr<CcnxPit>
+CcnxL3Protocol::GetPit()
+{
+ return m_pit;
+}
} //namespace ns3