HOWTOs are now on the wiki
This commit is contained in:
@@ -1,203 +0,0 @@
|
||||
/*!
|
||||
\page application How to create a traffic generator ?
|
||||
\anchor howtos-application
|
||||
|
||||
<b>Question:</b> How do I create a new traffic generator ?
|
||||
|
||||
<b>Answer:</b> It is possible to instanciate \ref ns3::Packet "Packet"
|
||||
objects, schedule events, and call functions from any piece of code
|
||||
in ns-3 so, technically, there is no single answer to the question of
|
||||
how we can write a new traffic generator. However, the
|
||||
\ref ns3::Socket "Socket" API was really designed to be the single
|
||||
point of entry for traffic generators or traffic analysers and the
|
||||
\ref ns3::Application "Application" class was designed to hold
|
||||
together any number of sockets.
|
||||
|
||||
Implementing a new traffic generator thus boils down to:
|
||||
- implementing a new subclass of the \ref ns3::Application "Application"
|
||||
base class
|
||||
- instanciate one or many sockets within that application
|
||||
- start scheduling events when \ref ns3::Application::StartApplication "StartApplication"
|
||||
is called
|
||||
- stop scheduling events when \ref ns3::Application::StopApplication "StopApplication"
|
||||
is called
|
||||
- create packets and send them over one or many sockets in each event
|
||||
|
||||
The following "random" generator generates packets separated by a random
|
||||
delay and with a random size.
|
||||
|
||||
\code
|
||||
class RandomGenerator : public Application
|
||||
{
|
||||
public:
|
||||
RandomGenerator ();
|
||||
void SetDelay (RandomVariable delay);
|
||||
void SetSize (RandomVariable size);
|
||||
void SetRemote (std::string socketType,
|
||||
Address remote);
|
||||
private:
|
||||
virtual void StartApplication (void);
|
||||
virtual void StopApplication (void);
|
||||
void DoGenerate (void);
|
||||
|
||||
RandomVariable m_delay;
|
||||
RandomVariable m_size;
|
||||
Ptr<Socket> m_socket;
|
||||
};
|
||||
\endcode
|
||||
|
||||
The socket is created in the SetRemote method:
|
||||
\code
|
||||
void
|
||||
RandomGenerator::SetRemote (std::string socketType,
|
||||
Address remote)
|
||||
{
|
||||
TypeId tid = TypeId::LookupByName (socketType);
|
||||
m_socket = Socket::CreateSocket (GetNode (), tid);
|
||||
m_socket->Bind ();
|
||||
m_socket->ShutdownRecv ();
|
||||
m_socket->Connect (remote);
|
||||
}
|
||||
\endcode
|
||||
While the the crux of the logic is located in the DoGenerate method
|
||||
which is called from within StartApplication:
|
||||
\code
|
||||
void
|
||||
RandomGenerator::DoGenerate (void)
|
||||
{
|
||||
m_next = Simulator::Schedule (Seconds (m_delay.GetValue ()),
|
||||
&RandomGenerator::DoGenerate, this);
|
||||
Ptr<Packet> p = Create<Packet> (m_size.GetIntValue ());
|
||||
m_socket->Send (p);
|
||||
}
|
||||
\endcode
|
||||
|
||||
To make that application more integrated in ns-3, it needs an associated
|
||||
helper class:
|
||||
\code
|
||||
class RandomAppHelper
|
||||
{
|
||||
public:
|
||||
RandomAppHelper (std::string protocol, Address remote);
|
||||
void SetPacketSize (RandomVariable packetSize);
|
||||
void SetDelay (RandomVariable delay);
|
||||
ApplicationContainer Install (NodeContainer nodes);
|
||||
private:
|
||||
std::string m_protocol;
|
||||
Address m_remote;
|
||||
RandomVariable m_packetSize;
|
||||
RandomVariable m_delay;
|
||||
};
|
||||
\endcode
|
||||
|
||||
which could be trivially implemented as:
|
||||
\code
|
||||
ApplicationContainer
|
||||
RandomAppHelper::Install (NodeContainer nodes)
|
||||
{
|
||||
ApplicationContainer applications;
|
||||
for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i)
|
||||
{
|
||||
Ptr<RandomAppHelper> app = CreateObject<RandomAppHelper> ();
|
||||
app->SetSize (m_packetSize);
|
||||
app->SetDelay (m_delay);
|
||||
app->SetRemote (m_protocol, m_remote);
|
||||
(*i)->AddApplication (app);
|
||||
applications.Add (app);
|
||||
}
|
||||
return applications;
|
||||
}
|
||||
\endcode
|
||||
|
||||
Despite being functional, this API is not very consistant with the style of
|
||||
the other helper classes, all of which allow you to control the parameters
|
||||
of the underlying class through attributes and not explicit setters. The
|
||||
following API thus replaces the pair SetPacketSize/SetDelay with a single
|
||||
method SetAttribute:
|
||||
\code
|
||||
class RandomAppHelper
|
||||
{
|
||||
public:
|
||||
RandomAppHelper (std::string protocol, Address remote);
|
||||
void SetAttribute (std::string name, const AttributeValue &value);
|
||||
ApplicationContainer Install (NodeContainer c);
|
||||
private:
|
||||
std::string m_protocol;
|
||||
Address m_remote;
|
||||
ObjectFactory m_factory;
|
||||
};
|
||||
\endcode
|
||||
|
||||
And which can be used as follows:
|
||||
\code
|
||||
RandomAppHelper app = RandomAppHelper ("ns3::TcpSocketFactory",
|
||||
InetSocketAddress (Ipv4Address ("192.168.1.10"), 10));
|
||||
app.SetAttribute ("Delay", StringValue ("Constant:2.5"));
|
||||
app.SetAttribute ("Size", StringValue ("Constant:2100"));
|
||||
app.Install (nodes);
|
||||
\endcode
|
||||
|
||||
The implementation, in this case, is not necessarily longer but its
|
||||
simplicity hides a lot of behind-the-scenes complexity:
|
||||
|
||||
\code
|
||||
void
|
||||
RandomAppHelper::SetAttribute (std::string name, const AttributeValue &value)
|
||||
{
|
||||
m_factory.Set (name, value);
|
||||
}
|
||||
ApplicationContainer
|
||||
RandomAppHelper::Install (NodeContainer nodes)
|
||||
{
|
||||
ApplicationContainer applications;
|
||||
for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i)
|
||||
{
|
||||
Ptr<RandomAppHelper> app = m_factory.Create<RandomAppHelper> ();
|
||||
app->SetRemote (m_socketType, m_remote);
|
||||
(*i)->AddApplication (app);
|
||||
applications.Add (app);
|
||||
}
|
||||
return applications;
|
||||
}
|
||||
\endcode
|
||||
|
||||
The key difference between this implementation and the previous one
|
||||
is that this helper does not handle explicitely the attributes
|
||||
delay and packet size. Instead, it stores them in an
|
||||
\ref ns3::ObjectFactory "ObjectFactory" object. This, of course,
|
||||
does not work magically, and requires extra support from the
|
||||
underlying RandomGenerator class. Specifically, it requires
|
||||
that the underlying RandomGenerator defines its attributes
|
||||
in its \ref ns3::TypeId "TypeId" in a new public static method:
|
||||
|
||||
\code
|
||||
class RandomGenerator
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
};
|
||||
\endcode
|
||||
|
||||
The corresponding implementation is shown below:
|
||||
|
||||
\code
|
||||
TypeId
|
||||
RandomGenerator::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("RandomGenerator")
|
||||
.SetParent<Application> ()
|
||||
.AddConstructor<RandomGenerator> ()
|
||||
.AddAttribute ("Delay", "The delay between two packets (s)",
|
||||
RandomVariableValue (ConstantVariable (1.0)),
|
||||
MakeRandomVariableAccessor (&RandomGenerator::m_delay),
|
||||
MakeRandomVariableChecker ())
|
||||
.AddAttribute ("PacketSize", "The size of each packet (bytes)",
|
||||
RandomVariableValue (ConstantVariable (2000)),
|
||||
MakeRandomVariableAccessor (&RandomGenerator::m_size),
|
||||
MakeRandomVariableChecker ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
\endcode
|
||||
|
||||
*/
|
||||
@@ -1,38 +0,0 @@
|
||||
/*!
|
||||
\page callbacks Using ns-3 callbacks
|
||||
\anchor howtos-callbacks
|
||||
|
||||
\section null_callbacks Null Callbacks
|
||||
|
||||
<b>Question:</b> The API I am using calls for using a callback (in the
|
||||
function signature), but I do not
|
||||
want to provide one. Is there a way to provide a null callback?
|
||||
|
||||
<b>Answer:</b> Use the ns3::MakeNullCallback construct:
|
||||
\code
|
||||
template<typename R>
|
||||
Callback< R, T1, T2, T3, T4, T5, T6 > ns3::MakeNullCallback (void)
|
||||
\endcode
|
||||
|
||||
Example usage: The ns3::Socket class uses callbacks to indicate completion
|
||||
of events such as a successful TCP connect(). These callbacks are set
|
||||
in the following function:
|
||||
\code
|
||||
void Socket::SetConnectCallback (Callback<void, Ptr<Socket> > connectionSucceeded,
|
||||
Callback<void, Ptr<Socket> > connectionFailed,
|
||||
Callback<void, Ptr<Socket> > halfClose);
|
||||
|
||||
\endcode
|
||||
But suppose you do not care about registering a callback for the
|
||||
halfClose event (but you want to register one for the
|
||||
connectionSucceeded and connectionFailed cases). In that case, you
|
||||
can pass a null callback as the third argument. You just need to
|
||||
pass a callback with the matching signature, as follows:
|
||||
\code
|
||||
localSocket->SetConnectCallback (
|
||||
MakeCallback (&ConnectionSucceededCallback),
|
||||
MakeCallback (&ConnectionFailedCallback),
|
||||
MakeNullCallback<void, Ptr<Socket> > () );
|
||||
\endcode
|
||||
|
||||
*/
|
||||
@@ -1,162 +0,0 @@
|
||||
/*!
|
||||
\page net-device How to create a new OSI layer 1 + 2 implementation ?
|
||||
\anchor howtos-net-device
|
||||
|
||||
<b>Question:</b> How do I integrate a new OSI layer 1 + 2 implementation ?
|
||||
|
||||
<b>Answer:</b> The OSI layers 1 and 2 are represented by the ns3::NetDevice
|
||||
and ns3::Channel classes. To plug transparently in ns-3, a new layer 1+2 model
|
||||
thus simply needs to provide two new subclasses of these two base classes.
|
||||
|
||||
To make that subclassing process easy, two skeleton classes are provided in
|
||||
the src/node directory: simple-net-device.h (ns3::SimpleNetDevice) and
|
||||
simple-channel.h (ns3::SimpleChannel) implement a broadcast passthru medium
|
||||
using 48bit MAC addresses without any kind of MAC access algorithm or PHY
|
||||
layer modeling.
|
||||
|
||||
The ns3::SimpleChannel class is really very simple: it provides
|
||||
an implementation for the ns3::Channel::GetNDevices and ns3::Channel::GetDevice
|
||||
methods defined in the Channel base class and, then defines the channel-specific
|
||||
send and add methods:
|
||||
- The Add method is used by SimpleNetDevice::SetChannel to register a new
|
||||
SimpleNetDevice with its associated channel.
|
||||
- The Send method is used by SimpleNetDevice::Send to send a packet over the
|
||||
broadcast medium and ensure that it gets delivered to all associated devices
|
||||
(except the sender).
|
||||
|
||||
\code
|
||||
class SimpleChannel : public Channel
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
SimpleChannel ();
|
||||
|
||||
void Send (Ptr<Packet> p, uint16_t protocol, Mac48Address to, Mac48Address from,
|
||||
Ptr<SimpleNetDevice> sender);
|
||||
|
||||
void Add (Ptr<SimpleNetDevice> device);
|
||||
|
||||
// inherited from ns3::Channel
|
||||
virtual uint32_t GetNDevices (void) const;
|
||||
virtual Ptr<NetDevice> GetDevice (uint32_t i) const;
|
||||
|
||||
private:
|
||||
std::vector<Ptr<SimpleNetDevice> > m_devices;
|
||||
};
|
||||
\endcode
|
||||
|
||||
The SimpleNetDevice class is also trivial since it implements no special
|
||||
MAC-layer processing:
|
||||
\code
|
||||
class SimpleNetDevice : public NetDevice
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
SimpleNetDevice ();
|
||||
|
||||
void Receive (Ptr<Packet> packet, uint16_t protocol, Mac48Address to, Mac48Address from);
|
||||
void SetChannel (Ptr<SimpleChannel> channel);
|
||||
void SetAddress (Mac48Address address);
|
||||
|
||||
// inherited from NetDevice base class.
|
||||
virtual void SetName(const std::string name);
|
||||
...
|
||||
};
|
||||
\endcode
|
||||
|
||||
The code below illustrates how the three model-specific methods defined above are
|
||||
implemented:
|
||||
|
||||
\code
|
||||
void
|
||||
SimpleNetDevice::Receive (Ptr<Packet> packet, uint16_t protocol,
|
||||
Mac48Address to, Mac48Address from)
|
||||
{
|
||||
if (to == m_address || to == Mac48Address::GetBroadcast ())
|
||||
{
|
||||
m_rxCallback (this, packet, protocol, from);
|
||||
}
|
||||
}
|
||||
void
|
||||
SimpleNetDevice::SetChannel (Ptr<SimpleChannel> channel)
|
||||
{
|
||||
m_channel = channel;
|
||||
m_channel->Add (this);
|
||||
}
|
||||
void
|
||||
SimpleNetDevice::SetAddress (Mac48Address address)
|
||||
{
|
||||
m_address = address;
|
||||
}
|
||||
\endcode
|
||||
|
||||
Building a topology with such a device is then a matter of
|
||||
instanciating a set of SimpleNetDevice objects connected on a shared
|
||||
SimpleChannel:
|
||||
\code
|
||||
NodeContainer nodes;
|
||||
nodes.Create (10);
|
||||
Ptr<SimpleChannel> channel = CreateObject<SimpleChannel> ();
|
||||
for (uint32_t i = 0; i < nodes.GetN (); ++i)
|
||||
{
|
||||
CreateSimpleDevice (nodes.Get (i), channel);
|
||||
}
|
||||
\endcode
|
||||
|
||||
With the following CreateSimpleDevice function:
|
||||
\code
|
||||
static Ptr<SimpleNetDevice>
|
||||
CreateSimpleDevice (Ptr<Node> node, Ptr<SimpleChannel> channel)
|
||||
{
|
||||
Ptr<SimpleNetDevice> device = CreateObject<SimpleNetDevice> ();
|
||||
device->SetAddress (Mac48Address:Allocate ());
|
||||
device->SetChannel (channel);
|
||||
node->AddDevice (device);
|
||||
return device;
|
||||
}
|
||||
\endcode
|
||||
|
||||
Of course, ultimately, you need to provide a helper class for this new device and channel
|
||||
to save each user from having to re-implement their own CreateSimpleDevice helper
|
||||
function:
|
||||
|
||||
\code
|
||||
class SimpleHelper
|
||||
{
|
||||
public:
|
||||
NetDeviceContainer Install (NodeContainer nodes, Ptr<SimpleChannel> channel);
|
||||
NetDeviceContainer Install (NodeContainer nodes);
|
||||
};
|
||||
\endcode
|
||||
|
||||
with the following straightforward implementation, inspired by the CreateSimpleDevice
|
||||
function defined above:
|
||||
|
||||
\code
|
||||
NetDeviceContainer
|
||||
SimpleHelper::Install (NodeContainer nodes, Ptr<SimpleChannel> channel)
|
||||
{
|
||||
NetDeviceContainer devices;
|
||||
for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i)
|
||||
{
|
||||
Ptr<SimpleNetDevice> dev = CreateObject<SimpleNetDevice> ();
|
||||
dev->SetAddress (Mac48Address::Allocate ());
|
||||
dev->SetChannel (channel);
|
||||
(*i)->AddDevice (dev);
|
||||
devices.Add (dev);
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
NetDeviceContainer
|
||||
SimpleHelper::Install (NodeContainer nodes)
|
||||
{
|
||||
return Install (nodes, CreateObject<SimpleChannel> ());
|
||||
}
|
||||
\endcode
|
||||
|
||||
Of course, at some point, this device helper class should also contain a couple of
|
||||
ascii and pcap tracing helper functions but, since the default SimpleNetDevice
|
||||
class we used as an example here does not report any trace event, it would
|
||||
be of little use.
|
||||
|
||||
*/
|
||||
@@ -1,119 +0,0 @@
|
||||
/*!
|
||||
\page packet-header-trailer How to create a new type of protocol header or trailer
|
||||
\anchor howtos-packet-header-trailer
|
||||
|
||||
<b>Question:</b> I want to implement a new protocol X which uses a new
|
||||
type of header Y. How do I implement and use this new header Y in ns-3 ?
|
||||
|
||||
<b>Answer:</b> The key is to implement a new subclass of the ns3::Header
|
||||
base class to represent your protocol header:
|
||||
\code
|
||||
class YHeader : public Header
|
||||
{
|
||||
public:
|
||||
// must be implemented to become a valid new header.
|
||||
static TypeId GetTypeId (void);
|
||||
virtual TypeId GetInstanceTypeId (void) const;
|
||||
virtual uint32_t GetSerializedSize (void) const;
|
||||
virtual void Serialize (Buffer::Iterator start) const;
|
||||
virtual uint32_t Deserialize (Buffer::Iterator start);
|
||||
virtual void Print (std::ostream &os) const;
|
||||
|
||||
// allow protocol-specific access to the header data.
|
||||
void SetData (uint32_t data);
|
||||
uint32_t GetData (void) const;
|
||||
private:
|
||||
uint32_t m_data;
|
||||
};
|
||||
\endcode
|
||||
|
||||
Once this class is implemented, you can easily store your protocol
|
||||
header into a packet:
|
||||
\code
|
||||
Ptr<Packet> p = ...;
|
||||
YHeader yHeader;
|
||||
yHeader.SetData (0xdeadbeaf);
|
||||
// copy the header into the packet
|
||||
p->AddHeader (yHeader);
|
||||
\endcode
|
||||
and get it out of a packet:
|
||||
\code
|
||||
Ptr<Packet> p = ...;
|
||||
YHeader yHeader;
|
||||
// copy the header from the packet
|
||||
p->RemoveHeader (yHeader);
|
||||
uint32_t data = yHeader.GetData ();
|
||||
\endcode
|
||||
|
||||
The implementation of the new header is very simple. First, you need
|
||||
to give a TypeId to your YHeader class:
|
||||
\code
|
||||
TypeId
|
||||
YHeader::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("YHeader")
|
||||
.SetParent<Header> ()
|
||||
.AddConstructor<YHeader> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
TypeId
|
||||
YHeader::GetInstanceTypeId (void)
|
||||
{
|
||||
return GetTypeId ();
|
||||
}
|
||||
\endcode
|
||||
|
||||
Then, you need to allow your header to serialize and deserialize itself
|
||||
to a byte buffer in its network representation. Here, our new protocol
|
||||
header contains first a 2-byte constant, and, then, the data field so,
|
||||
the total size of the header is 2+4=6 bytes.
|
||||
\code
|
||||
uint32_t
|
||||
YHeader::GetSerializedSize (void) const
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
void
|
||||
YHeader::Serialize (Buffer::Iterator start) const
|
||||
{
|
||||
// The 2 byte-constant
|
||||
start.WriteU8 (0xfe);
|
||||
start.WriteU8 (0xef);
|
||||
// The data.
|
||||
start.WriteHtonU32 (m_data);
|
||||
}
|
||||
uint32_t
|
||||
YHeader::Deserialize (Buffer::Iterator start)
|
||||
{
|
||||
uint8_t tmp;
|
||||
tmp = start.ReadU8 ();
|
||||
NS_ASSERT (tmp == 0xfe);
|
||||
tmp = start.ReadU8 ();
|
||||
NS_ASSERT (tmp == 0xef);
|
||||
m_data = start.ReadNtohU32 ();
|
||||
return 6; // the number of bytes consumed.
|
||||
}
|
||||
\endcode
|
||||
|
||||
Finally, to make sure that Packet::Print also prints the content
|
||||
of your header, just as it prints the content of the other
|
||||
headers of the system, you need to provide a Print method:
|
||||
\code
|
||||
void
|
||||
YHeader::Print (std::ostream &os) const
|
||||
{
|
||||
os << "data=" << m_data;
|
||||
}
|
||||
\endcode
|
||||
|
||||
The code will look the same if you want to implement a trailer,
|
||||
that is, a protocol data structure which will be appended to the
|
||||
end of the packet, not its start: you need to make sure that
|
||||
you derive from the ns3::Trailer base class and that you call
|
||||
Packet::AddTrailer and Packet::RemoveTrailer. Another important
|
||||
detail is that you must make sure to rewind the iterator in your
|
||||
Serialize and Deserialize methods writing to or reading from
|
||||
the underlying buffer.
|
||||
|
||||
*/
|
||||
@@ -1,20 +0,0 @@
|
||||
/*!
|
||||
\page howtos ns-3 HOWTOs
|
||||
\anchor howtos-anchor
|
||||
|
||||
This is an organized set of frequently asked questions (FAQ) and HOWTOs
|
||||
for ns-3. This complements the following wiki pages:
|
||||
|
||||
- <a href="http://www.nsnam.org/wiki/index.php/User_FAQ">User FAQ</a>
|
||||
- <a href="http://www.nsnam.org/wiki/index.php/Developer_FAQ">Developer FAQ</a>
|
||||
|
||||
Please consider contributing tips to either the wiki (yourself) or
|
||||
by submitting a patch to this maintained documentation.
|
||||
|
||||
- \subpage callbacks
|
||||
- \subpage packet-header-trailer
|
||||
- \subpage net-device
|
||||
- \subpage application
|
||||
|
||||
*/
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
* organizes all of the public API and supporting manual text
|
||||
* along the source code directory structure. This forms the
|
||||
* "ns-3 manual", and it is available in HTML and PDF forms.
|
||||
* - \ref howtos-anchor "HOWTOs": A set of HOWTOs and FAQs is
|
||||
* maintained on another Doxygen "Related Page"
|
||||
* - <a href="http://www.nsnam.org/docs/tutorial/tutorial.html">tutorial</a>: The ns-3 tutorial is a separate document maintained in <a href="http://www.gnu.org/software/texinfo/"> GNU Texinfo</a>.
|
||||
* - <a href="http://www.nsnam.org/docs/manual/manual.html">Reference manual</a>: The ns-3 tutorial is a separate document maintained in <a href="http://www.gnu.org/software/texinfo/"> GNU Texinfo</a>.
|
||||
* - <a href="http://www.nsnam.org/docs/testing/testing.html">Testing and validation manual</a>: The ns-3 tutorial is a separate document maintained in <a href="http://www.gnu.org/software/texinfo/"> GNU Texinfo</a>.
|
||||
* - The <b><a href="http://www.nsnam.org/wiki/index.php/Main_Page">ns-3 wiki</a></b>
|
||||
* contains additional user-contributed material. Some wiki-contributed
|
||||
* material may migrate to and overlap with the Doxygen information.
|
||||
* material may migrate to and overlap with the Doxygen and manual information.
|
||||
*
|
||||
* \section install-sec Building the Documentation
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user