One more change in Consumer API. Now there are more consumers and they
behave slightly differently (CcnxConsumerCbr accepts only Frequency parameter)
More corrections in blackhole-sprint scenario
diff --git a/apps/ccnx-consumer-batches.cc b/apps/ccnx-consumer-batches.cc
new file mode 100644
index 0000000..deb4a0d
--- /dev/null
+++ b/apps/ccnx-consumer-batches.cc
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "ccnx-consumer-batches.h"
+#include "ns3/ptr.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ns3/packet.h"
+#include "ns3/callback.h"
+#include "ns3/string.h"
+#include "ns3/uinteger.h"
+#include "ns3/double.h"
+#include "ns3/batches.h"
+
+NS_LOG_COMPONENT_DEFINE ("CcnxConsumerBatches");
+
+namespace ns3
+{
+
+NS_OBJECT_ENSURE_REGISTERED (CcnxConsumerBatches);
+
+TypeId
+CcnxConsumerBatches::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::CcnxConsumerBatches")
+ .SetParent<CcnxConsumer> ()
+ .AddConstructor<CcnxConsumerBatches> ()
+
+ .AddAttribute ("Batches", "Batches to schedule. Should be vector, containing pairs of time and amount",
+ // TypeId::ATTR_SET,
+ StringValue (""),
+ MakeBatchesAccessor (&CcnxConsumerBatches::GetBatch, &CcnxConsumerBatches::SetBatch),
+ MakeBatchesChecker ())
+ ;
+
+ return tid;
+}
+
+CcnxConsumerBatches::CcnxConsumerBatches ()
+{
+}
+
+void
+CcnxConsumerBatches::SetBatch (const Batches &batches)
+{
+ // std::cout << "Batches: " << batches << "\n";
+ for (Batches::const_iterator i = batches.begin (); i != batches.end (); i++)
+ {
+ Simulator::Schedule (i->get<0> (), &CcnxConsumerBatches::AddBatch, this, i->get<1> ());
+ }
+}
+
+void
+CcnxConsumerBatches::AddBatch (uint32_t amount)
+{
+ // std::cout << Simulator::Now () << " adding batch of " << amount << "\n";
+ m_seqMax += amount;
+ ScheduleNextPacket ();
+}
+
+void
+CcnxConsumerBatches::ScheduleNextPacket ()
+{
+ if (!m_sendEvent.IsRunning ())
+ m_sendEvent = Simulator::Schedule (Seconds(0.00001), &CcnxConsumer::SendPacket, this);
+}
+
+///////////////////////////////////////////////////
+// Process incoming packets //
+///////////////////////////////////////////////////
+
+} // namespace ns3
diff --git a/apps/ccnx-consumer-batches.h b/apps/ccnx-consumer-batches.h
new file mode 100644
index 0000000..36d7643
--- /dev/null
+++ b/apps/ccnx-consumer-batches.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef CCNX_CONSUMER_BATCHES_H
+#define CCNX_CONSUMER_BATCHES_H
+
+#include "ccnx-consumer.h"
+#include "ns3/traced-value.h"
+#include "ns3/batches.h"
+
+namespace ns3
+{
+
+/**
+ * @ingroup ccnx
+ * \brief CCNx application for sending out Interest packets in batches
+ */
+class CcnxConsumerBatches: public CcnxConsumer
+{
+public:
+ static TypeId GetTypeId ();
+
+ /**
+ * \brief Default constructor
+ */
+ CcnxConsumerBatches ();
+
+ // From CcnxApp
+ // virtual void
+ // OnInterest (const Ptr<const CcnxInterestHeader> &interest);
+
+ // virtual void
+ // OnNack (const Ptr<const CcnxInterestHeader> &interest);
+
+ // virtual void
+ // OnContentObject (const Ptr<const CcnxContentObjectHeader> &contentObject,
+ // const Ptr<const Packet> &payload);
+
+ // virtual void
+ // OnTimeout (uint32_t sequenceNumber);
+
+private:
+ Batches
+ GetBatch () const { return Batches(); }
+
+ void
+ SetBatch (const Batches &batch);
+
+ void
+ AddBatch (uint32_t amount);
+protected:
+ /**
+ * \brief Constructs the Interest packet and sends it using a callback to the underlying CCNx protocol
+ */
+ virtual void
+ ScheduleNextPacket ();
+};
+
+} // namespace ns3
+
+#endif
diff --git a/apps/ccnx-consumer-cbr.cc b/apps/ccnx-consumer-cbr.cc
index b001ba7..a7b848c 100644
--- a/apps/ccnx-consumer-cbr.cc
+++ b/apps/ccnx-consumer-cbr.cc
@@ -48,62 +48,31 @@
.SetParent<CcnxConsumer> ()
.AddConstructor<CcnxConsumerCbr> ()
- .AddAttribute ("MeanRate", "Mean data packet rate (relies on the PayloadSize parameter)",
- StringValue ("100Kbps"),
- MakeDataRateAccessor (&CcnxConsumerCbr::GetDesiredRate, &CcnxConsumerCbr::SetDesiredRate),
- MakeDataRateChecker ())
+ .AddAttribute ("Frequency", "Frequency of interest packets",
+ StringValue ("1.0"),
+ MakeDoubleAccessor (&CcnxConsumerCbr::m_frequency),
+ MakeDoubleChecker<double> ())
;
return tid;
}
CcnxConsumerCbr::CcnxConsumerCbr ()
- : m_desiredRate ("100Kbps")
+ : m_frequency (1.0)
{
NS_LOG_FUNCTION_NOARGS ();
-
- UpdateMean ();
}
-
-void
-CcnxConsumerCbr::UpdateMean ()
-{
- double mean = 8.0 * m_payloadSize / m_desiredRate.GetBitRate ();
- m_randExp = ExponentialVariable (mean, 100 * mean); // set upper limit to inter-arrival time
-}
-
-void
-CcnxConsumerCbr::SetPayloadSize (uint32_t payload)
-{
- CcnxConsumer::SetPayloadSize (payload);
- UpdateMean ();
-}
-
-void
-CcnxConsumerCbr::SetDesiredRate (DataRate rate)
-{
- m_desiredRate = rate;
- UpdateMean ();
-}
-
-DataRate
-CcnxConsumerCbr::GetDesiredRate () const
-{
- return m_desiredRate;
-}
-
-
void
CcnxConsumerCbr::ScheduleNextPacket ()
{
- double mean = 8.0 * m_payloadSize / m_desiredRate.GetBitRate ();
+ // double mean = 8.0 * m_payloadSize / m_desiredRate.GetBitRate ();
// std::cout << "next: " << Simulator::Now().ToDouble(Time::S) + mean << "s\n";
if (!m_sendEvent.IsRunning ())
m_sendEvent = Simulator::Schedule (
// Seconds(m_randExp.GetValue ()),
- Seconds(mean),
+ Seconds(1.0 / m_frequency),
&CcnxConsumer::SendPacket, this);
}
diff --git a/apps/ccnx-consumer-cbr.h b/apps/ccnx-consumer-cbr.h
index 59a06d7..03558ed 100644
--- a/apps/ccnx-consumer-cbr.h
+++ b/apps/ccnx-consumer-cbr.h
@@ -61,21 +61,21 @@
ScheduleNextPacket ();
private:
- void
- UpdateMean ();
+ // void
+ // UpdateMean ();
- virtual void
- SetPayloadSize (uint32_t payload);
+ // virtual void
+ // SetPayloadSize (uint32_t payload);
- void
- SetDesiredRate (DataRate rate);
+ // void
+ // SetDesiredRate (DataRate rate);
- DataRate
- GetDesiredRate () const;
+ // DataRate
+ // GetDesiredRate () const;
protected:
ExponentialVariable m_randExp; // packet inter-arrival time generation (Poisson process)
- DataRate m_desiredRate; // Desired data packet rate
+ double m_frequency; // Frequency of interest packets (in hertz)
};
} // namespace ns3
diff --git a/apps/ccnx-consumer-window.cc b/apps/ccnx-consumer-window.cc
index 77f258c..060b2cc 100644
--- a/apps/ccnx-consumer-window.cc
+++ b/apps/ccnx-consumer-window.cc
@@ -47,6 +47,15 @@
MakeUintegerAccessor (&CcnxConsumerWindow::GetWindow, &CcnxConsumerWindow::SetWindow),
MakeUintegerChecker<uint32_t> ())
+ .AddAttribute ("PayloadSize", "Average size of content object size (to calculate interest generation rate)",
+ UintegerValue (1040),
+ MakeUintegerAccessor (&CcnxConsumerWindow::GetPayloadSize, &CcnxConsumerWindow::SetPayloadSize),
+ MakeUintegerChecker<uint32_t>())
+ .AddAttribute ("Size", "Amount of data in megabytes to request (relies on PayloadSize parameter)",
+ DoubleValue (-1), // don't impose limit by default
+ MakeDoubleAccessor (&CcnxConsumerWindow::GetMaxSize, &CcnxConsumerWindow::SetMaxSize),
+ MakeDoubleChecker<double> ())
+
.AddTraceSource ("WindowTrace",
"Window that controls how many outstanding interests are allowed",
MakeTraceSourceAccessor (&CcnxConsumerWindow::m_window))
@@ -59,7 +68,8 @@
}
CcnxConsumerWindow::CcnxConsumerWindow ()
- : m_inFlight (0)
+ : m_payloadSize (1040)
+ , m_inFlight (0)
{
}
@@ -75,6 +85,42 @@
return m_window;
}
+uint32_t
+CcnxConsumerWindow::GetPayloadSize () const
+{
+ return m_payloadSize;
+}
+
+void
+CcnxConsumerWindow::SetPayloadSize (uint32_t payload)
+{
+ m_payloadSize = payload;
+}
+
+double
+CcnxConsumerWindow::GetMaxSize () const
+{
+ if (m_seqMax == 0)
+ return -1.0;
+
+ return m_maxSize;
+}
+
+void
+CcnxConsumerWindow::SetMaxSize (double size)
+{
+ m_maxSize = size;
+ if (m_maxSize < 0)
+ {
+ m_seqMax = 0;
+ return;
+ }
+
+ m_seqMax = floor(1.0 + m_maxSize * 1024.0 * 1024.0 / m_payloadSize);
+ NS_LOG_DEBUG ("MaxSeqNo: " << m_seqMax);
+}
+
+
void
CcnxConsumerWindow::ScheduleNextPacket ()
{
diff --git a/apps/ccnx-consumer-window.h b/apps/ccnx-consumer-window.h
index c3b0ddf..0c24551 100644
--- a/apps/ccnx-consumer-window.h
+++ b/apps/ccnx-consumer-window.h
@@ -69,8 +69,23 @@
uint32_t
GetWindow () const;
+
+ virtual void
+ SetPayloadSize (uint32_t payload);
+
+ uint32_t
+ GetPayloadSize () const;
+
+ double
+ GetMaxSize () const;
+
+ void
+ SetMaxSize (double size);
protected:
+ uint32_t m_payloadSize; // expected payload size
+ double m_maxSize; // max size to request
+
TracedValue<uint32_t> m_window;
TracedValue<uint32_t> m_inFlight;
};
diff --git a/apps/ccnx-consumer.cc b/apps/ccnx-consumer.cc
index 28dc23e..6c58bc7 100644
--- a/apps/ccnx-consumer.cc
+++ b/apps/ccnx-consumer.cc
@@ -58,15 +58,6 @@
MakeIntegerAccessor(&CcnxConsumer::m_seq),
MakeIntegerChecker<int32_t>())
- .AddAttribute ("PayloadSize", "Average size of content object size (to calculate interest generation rate)",
- UintegerValue (1040),
- MakeUintegerAccessor (&CcnxConsumer::GetPayloadSize, &CcnxConsumer::SetPayloadSize),
- MakeUintegerChecker<uint32_t>())
- .AddAttribute ("Size", "Amount of data in megabytes to request (relies on PayloadSize parameter)",
- DoubleValue (-1), // don't impose limit by default
- MakeDoubleAccessor (&CcnxConsumer::GetMaxSize, &CcnxConsumer::SetMaxSize),
- MakeDoubleChecker<double> ())
-
.AddAttribute ("Prefix","CcnxName of the Interest",
StringValue ("/"),
MakeCcnxNameComponentsAccessor (&CcnxConsumer::m_interestName),
@@ -94,7 +85,7 @@
.AddAttribute ("RetxTimer",
"Timeout defining how frequent retransmission timeouts should be checked",
- StringValue ("1s"),
+ StringValue ("1ms"),
MakeTimeAccessor (&CcnxConsumer::GetRetxTimer, &CcnxConsumer::SetRetxTimer),
MakeTimeChecker ())
@@ -107,8 +98,8 @@
CcnxConsumer::CcnxConsumer ()
: m_rand (0, std::numeric_limits<uint32_t>::max ())
- , m_payloadSize (1040)
, m_seq (0)
+ , m_seqMax (0) // don't request anything
{
NS_LOG_FUNCTION_NOARGS ();
@@ -159,40 +150,6 @@
&CcnxConsumer::CheckRetxTimeout, this);
}
-uint32_t
-CcnxConsumer::GetPayloadSize () const
-{
- return m_payloadSize;
-}
-
-void
-CcnxConsumer::SetPayloadSize (uint32_t payload)
-{
- m_payloadSize = payload;
-}
-
-double
-CcnxConsumer::GetMaxSize () const
-{
- if (m_seqMax == 0)
- return -1.0;
-
- return m_seqMax * m_payloadSize / 1024.0 / 1024.0;
-}
-
-void
-CcnxConsumer::SetMaxSize (double size)
-{
- if (size < 0)
- {
- m_seqMax = 0;
- return;
- }
-
- m_seqMax = floor(1.0 + size * 1024.0 * 1024.0 / m_payloadSize);
- NS_LOG_DEBUG ("MaxSeqNo: " << m_seqMax);
-}
-
// Application Methods
void
CcnxConsumer::StartApplication () // Called at time specified by Start
@@ -354,8 +311,8 @@
void
CcnxConsumer::OnTimeout (uint32_t sequenceNumber)
{
- // std::cout << "TO: " << sequenceNumber << "\n";
- // std::cout << "Current RTO: " << m_rtt->RetransmitTimeout ().ToDouble (Time::S) << "s\n";
+ std::cout << Simulator::Now () << ", TO: " << sequenceNumber << ", current RTO: " << m_rtt->RetransmitTimeout ().ToDouble (Time::S) << "s\n";
+
m_retxSeqs.insert (sequenceNumber);
ScheduleNextPacket ();
}
diff --git a/apps/ccnx-consumer.h b/apps/ccnx-consumer.h
index 8fe885d..e53ff89 100644
--- a/apps/ccnx-consumer.h
+++ b/apps/ccnx-consumer.h
@@ -109,21 +109,8 @@
Time
GetRetxTimer () const;
- virtual void
- SetPayloadSize (uint32_t payload);
-
- uint32_t
- GetPayloadSize () const;
-
- double
- GetMaxSize () const;
-
- void
- SetMaxSize (double size);
-
protected:
UniformVariable m_rand; // nonce generator
- uint32_t m_payloadSize; // expected payload size
uint32_t m_seq;
uint32_t m_seqMax; // maximum number of sequence number
diff --git a/apps/ccnx-hijacker.cc b/apps/ccnx-hijacker.cc
index c0d74d7..0bcad9d 100644
--- a/apps/ccnx-hijacker.cc
+++ b/apps/ccnx-hijacker.cc
@@ -31,6 +31,9 @@
#include "ns3/ccnx-fib.h"
#include <boost/ref.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/lambda/bind.hpp>
+namespace ll = boost::lambda;
NS_LOG_COMPONENT_DEFINE ("CcnxHijacker");
@@ -75,7 +78,13 @@
CcnxApp::StartApplication ();
- GetNode ()->GetObject<CcnxFib> ()->Add (m_prefix, m_face, 0);
+ Ptr<CcnxFib> fib = GetNode ()->GetObject<CcnxFib> ();
+ CcnxFibEntryContainer::type::iterator fibEntry = fib->Add (m_prefix, m_face, 0);
+
+ // make face green, so it will be used primarily
+ fib->m_fib.modify (fibEntry,
+ ll::bind (&CcnxFibEntry::UpdateStatus,
+ ll::_1, m_face, CcnxFibFaceMetric::NDN_FIB_GREEN));
}
void
diff --git a/apps/ccnx-producer.cc b/apps/ccnx-producer.cc
index 3a37efd..48c8991 100644
--- a/apps/ccnx-producer.cc
+++ b/apps/ccnx-producer.cc
@@ -31,6 +31,9 @@
#include "ns3/ccnx-fib.h"
#include <boost/ref.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/lambda/bind.hpp>
+namespace ll = boost::lambda;
NS_LOG_COMPONENT_DEFINE ("CcnxProducer");
@@ -75,7 +78,13 @@
CcnxApp::StartApplication ();
- GetNode ()->GetObject<CcnxFib> ()->Add (m_prefix, m_face, 0);
+ Ptr<CcnxFib> fib = GetNode ()->GetObject<CcnxFib> ();
+ CcnxFibEntryContainer::type::iterator fibEntry = fib->Add (m_prefix, m_face, 0);
+
+ // make face green, so it will be used primarily
+ fib->m_fib.modify (fibEntry,
+ ll::bind (&CcnxFibEntry::UpdateStatus,
+ ll::_1, m_face, CcnxFibFaceMetric::NDN_FIB_GREEN));
}
void
diff --git a/examples/base-experiment.h b/examples/base-experiment.h
index c00c127..fd8c1f0 100644
--- a/examples/base-experiment.h
+++ b/examples/base-experiment.h
@@ -111,8 +111,8 @@
{
guard ++;
- uint32_t node1_num = m_rand.GetValue ();
- uint32_t node2_num = m_rand.GetValue ();
+ uint32_t node1_num = m_rand.GetValue (); //43;//
+ uint32_t node2_num = m_rand.GetValue (); //38;//
if (node1_num == node2_num)
continue;
diff --git a/examples/blackhole-sprint.cc b/examples/blackhole-sprint.cc
index dba634a..8773ce3 100644
--- a/examples/blackhole-sprint.cc
+++ b/examples/blackhole-sprint.cc
@@ -255,6 +255,8 @@
uint32_t node1_num = i->get<0> ();
uint32_t node2_num = i->get<1> ();
+ cout << "Good: " << node1_num << ", bad: " << node2_num << "\n";
+
Ptr<Node> node1 = Names::Find<Node> ("/sprint", lexical_cast<string> (node1_num));
Ptr<Node> node2 = Names::Find<Node> ("/sprint", lexical_cast<string> (node2_num));
@@ -271,19 +273,21 @@
CcnxAppHelper fakeProducerHelper ("ns3::CcnxHijacker");
fakeProducerHelper.SetPrefix (prefix);
- apps.Add
- (fakeProducerHelper.Install (node2));
+ ApplicationContainer hijacker = fakeProducerHelper.Install (node2);
+ apps.Add (hijacker);
+ hijacker.Start (Seconds(1.0));
// one more trick. Need to install route to hijacker (aka "hijacker announces itself as a legitimate producer")
CcnxStackHelper::InstallRouteTo (prefix, node1);
- CcnxStackHelper::InstallRouteTo (prefix, node2);
+ Simulator::Schedule (Seconds(1.0), CcnxStackHelper::InstallRouteTo, prefix, node2);
+ // CcnxStackHelper::InstallRouteTo (prefix, node2);
prefixes.push_back (prefix); // remember prefixes that consumers will be requesting
}
// All consumers request exactly 10 packets, to convert number interests packets to requested size:
// size = 1040 * (max_number_of_packets-1) / 1024 / 1024
- double requestSize = 1040.0 * (10 - 1) / 1024.0 / 1024.0;
+ // double requestSize = 1040.0 * (10 - 1) / 1024.0 / 1024.0;
// Create Consumers
NodeContainer nodes = reader->GetNodes ();
@@ -293,16 +297,15 @@
if (m_usedNodes.count (namedId) > 0)
continue;
- CcnxAppHelper consumerHelper ("ns3::CcnxConsumerCbr");
+ CcnxAppHelper consumerHelper ("ns3::CcnxConsumerBatches");
consumerHelper.SetAttribute ("LifeTime", StringValue("100s"));
+ consumerHelper.SetAttribute ("Batches", StringValue("0s 10 2s 1"));
BOOST_FOREACH (const string &prefix, prefixes)
{
consumerHelper.SetPrefix (prefix);
- consumerHelper.SetAttribute ("MeanRate", StringValue ("1000Kbps")); // this is about 1 interest a second
- consumerHelper.SetAttribute ("Size", DoubleValue(requestSize));
-
- apps.Add
- (consumerHelper.Install (*node));
+
+ ApplicationContainer consumer = consumerHelper.Install (*node);
+ apps.Add (consumer);
}
// break;
@@ -335,18 +338,18 @@
// config.ConfigureDefaults ();
Experiment experiment;
- for (uint32_t i = startRun; i < maxRuns; i++)
+ for (uint32_t run = startRun; run < startRun + maxRuns; run++)
{
- Config::SetGlobal ("RngRun", IntegerValue (i));
+ Config::SetGlobal ("RngRun", IntegerValue (run));
cout << "seed = " << SeedManager::GetSeed () << ", run = " << SeedManager::GetRun () << endl;
Experiment experiment;
- experiment.GenerateRandomPairs (10);
+ experiment.GenerateRandomPairs (1);
experiment.ComputeShortestWeightsPath(1,12);
experiment.ComputeShortestDelayPath(1,12);
- cout << "Run " << i << endl;
+ cout << "Run " << run << endl;
- string prefix = "blackhole-" + lexical_cast<string> (i) + "-";
+ string prefix = "blackhole-" + lexical_cast<string> (run) + "-";
experiment.ConfigureTopology ();
experiment.InstallCcnxStack (false);
@@ -355,7 +358,7 @@
//tracing
CcnxTraceHelper traceHelper;
// traceHelper.EnableRateL3All (prefix + "rate-trace.log");
- traceHelper.EnableSeqsAppAll ("ns3::CcnxConsumerCbr", prefix + "consumers-seqs.log");
+ traceHelper.EnableSeqsAppAll ("ns3::CcnxConsumerBatches", prefix + "consumers-seqs.log");
experiment.Run (Seconds(40.0));
}
diff --git a/model/batches.cc b/model/batches.cc
new file mode 100644
index 0000000..1dbccfa
--- /dev/null
+++ b/model/batches.cc
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2011,2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "ns3/batches.h"
+
+namespace ns3 {
+
+ATTRIBUTE_HELPER_CPP (Batches);
+
+std::ostream &
+operator << (std::ostream &os, const Batches &batch)
+{
+ for (Batches::const_iterator i = batch.begin (); i != batch.end (); i++)
+ os << i->get<0> () << " " << i->get<1> () << " ";
+
+ return os;
+}
+
+/**
+ * \brief Read components from input and add them to components. Will read input stream till eof
+ * Substrings separated by slashes will become separate components
+ */
+std::istream &
+operator >> (std::istream &is, Batches &batch)
+{
+ Time time;
+ uint32_t amount;
+ while (!is.eof ())
+ {
+ is >> time >> amount;
+ batch.Add (time, amount);
+ // std::cout << time << ", " << amount << ". \n";
+ }
+
+ is.clear ();
+ return is;
+}
+
+
+}
diff --git a/model/batches.h b/model/batches.h
new file mode 100644
index 0000000..d481a47
--- /dev/null
+++ b/model/batches.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2011,2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef _BATCHES_H_
+#define _BATCHES_H_
+
+#include "ns3/attribute.h"
+#include "ns3/attribute-helper.h"
+#include "ns3/nstime.h"
+#include <list>
+#include <boost/tuple/tuple.hpp>
+
+namespace ns3 {
+
+class Batches : public std::list<boost::tuple<Time, uint32_t> >
+{
+public:
+ Batches () { };
+
+ void
+ Add (const Time &when, uint32_t amount)
+ {
+ push_back (boost::make_tuple<Time, uint32_t> (when, amount));
+ }
+};
+
+ATTRIBUTE_HELPER_HEADER (Batches);
+
+std::ostream &
+operator << (std::ostream &os, const Batches &batch);
+
+/**
+ * \brief Read components from input and add them to components. Will read input stream till eof
+ * Substrings separated by slashes will become separate components
+ */
+std::istream &
+operator >> (std::istream &is, Batches &batch);
+
+} // namespace ns3
+
+#endif // _BATCHES_H_
diff --git a/wscript b/wscript
index e33af19..d4b9bc9 100644
--- a/wscript
+++ b/wscript
@@ -80,6 +80,8 @@
"model/rocketfuel-weights-reader.h",
"model/annotated-topology-reader.h",
+
+ "model/batches.h"
]
tests.source = bld.path.ant_glob('test/*.cc');