338 lines
14 KiB
Plaintext
338 lines
14 KiB
Plaintext
@node Node and Internet Stack
|
|
@chapter Node and Internet Stack
|
|
@anchor{chap:Node}
|
|
|
|
This chapter describes how ns-3 nodes are put together, and provides
|
|
a walk-through of how packets traverse an internet-based Node.
|
|
|
|
@float Figure,fig:node
|
|
@caption{High-level node architecture.}
|
|
@image{figures/node,5in}
|
|
@end float
|
|
|
|
In ns-3, nodes are instances of @code{class Node}. This class
|
|
may be subclassed, but instead, the conceptual model is that
|
|
we @emph{aggregate} or insert objects to it rather than define
|
|
subclasses.
|
|
|
|
One might think of a bare ns-3 node as a shell of a computer,
|
|
to which one may add NetDevices (cards) and other innards including
|
|
the protocols and applications. @ref{fig:node} illustrates
|
|
that Node objects contain a list of Applications (initially,
|
|
the list is empty), a list of NetDevices (initially, the list
|
|
is empty), a unique integer ID, and a system ID (for
|
|
distributed simulation).
|
|
|
|
The design tries to avoid putting too many dependencies on the
|
|
base class Node, Application, or NetDevice for the following:
|
|
@itemize @bullet
|
|
@item IP version, or whether IP is at all even used in the Node.
|
|
@item implementation details of the IP stack
|
|
@end itemize
|
|
|
|
From a software perspective, the lower interface of applications
|
|
corresponds to the C-based sockets API. The upper interface
|
|
of NetDevice objects corresponds to the device independent
|
|
sublayer of the Linux stack. Everything in between can be
|
|
aggregated and plumbed together as needed.
|
|
|
|
Let's look more closely at the protocol demultiplexer. We want
|
|
incoming frames at layer-2 to be delivered to the right layer-3
|
|
protocol such as Ipv4. The
|
|
function of this demultiplexer is to register callbacks for
|
|
receiving packets. The callbacks are indexed based on the
|
|
@uref{http://en.wikipedia.org/wiki/EtherType,,EtherType}
|
|
in the layer-2 frame.
|
|
|
|
Many different types of higher-layer protocols may be
|
|
connected to the NetDevice, such as IPv4, IPv6, ARP,
|
|
MPLS, IEEE 802.1x, and packet sockets. Therefore, the
|
|
use of a callback-based demultiplexer avoids the need to
|
|
use a common base class for all of these protocols, which
|
|
is problematic because of the different types of objects
|
|
(including packet sockets) expected to be registered there.
|
|
|
|
Each NetDevice delivers packets to a callback with the following
|
|
signature:
|
|
@verbatim
|
|
/**
|
|
* \param device a pointer to the net device which is calling this callback
|
|
* \param packet the packet received
|
|
* \param protocol the 16 bit protocol number associated with this packet.
|
|
* This protocol number is expected to be the same protocol number
|
|
* given to the Send method by the user on the sender side.
|
|
* \param address the address of the sender
|
|
* \returns true if the callback could handle the packet successfully,
|
|
* false otherwise.
|
|
*/
|
|
typedef Callback<bool, Ptr<NetDevice>, Ptr<Packet>, uint16_t,
|
|
const Address &> ReceiveCallback;
|
|
@end verbatim
|
|
|
|
There is a function in class Node that matches that signature:
|
|
@verbatim
|
|
private:
|
|
bool ReceiveFromDevice (Ptr<NetDevice> device, Ptr<Packet>,
|
|
uint16_t protocol, const Address &from);
|
|
@end verbatim
|
|
|
|
However, users do not need to access this function directly. Instead,
|
|
when users call @code{uint32_t AddDevice (Ptr<NetDevice> device)},
|
|
the implementation of this function sets the callback (and the
|
|
function returns the ifIndex of the NetDevice on that Node).
|
|
|
|
But what does the ReceiveFromDevice function do? Here, it looks
|
|
up another callback, in its list of callbacks, corresponding to the
|
|
matching EtherType. This callback is called a ProtocolHandler, and
|
|
is specified as follows:
|
|
@verbatim
|
|
typedef Callback<void, Ptr<NetDevice>, Ptr<Packet>, uint16_t,
|
|
const Address &> ProtocolHandler;
|
|
@end verbatim
|
|
|
|
Upper-layer protocols or objects are expected to provide such a function.
|
|
and register it with the list of ProtocolHandlers by calling
|
|
@code{Node::RegisterProtocolHandler ();}
|
|
For instance, if Ipv4 is aggregated to a Node, then the Ipv4 receive
|
|
function can be registered with the protocol handler by calling:
|
|
@verbatim
|
|
RegisterProtocolHandler (
|
|
MakeCallback (&Ipv4L3Protocol::Receive, ipv4),
|
|
Ipv4L3Protocol::PROT_NUMBER, 0);
|
|
@end verbatim
|
|
and likewise for Ipv6, ARP, etc.
|
|
|
|
@section NodeList
|
|
|
|
Every Node created is automatically added to the ns-3 @code{NodeList}.
|
|
The NodeList class provides an @code{Add()} method and C++ iterators
|
|
to allow one to walk the node list or fetch a Node pointer by
|
|
its integer identifier.
|
|
|
|
@section Internet stack aggregation
|
|
|
|
The above @code{class Node} is not very useful as-is; other objects
|
|
must be aggregated to it to provide useful node functionality.
|
|
|
|
The ns-3 source code directory @code{src/internet-stack} provides
|
|
implementation of TCP/IPv4-related components. These include IPv4,
|
|
ARP, UDP, TCP, and other related protocols.
|
|
|
|
Internet Nodes are not subclasses of class Node; they are simply Nodes
|
|
that have had a bunch of IPv4-related
|
|
objects aggregated to them. They can be put together by hand, or
|
|
via a helper function @code{InternetStackHelper::Install ()} which does the
|
|
following to all nodes passed in as arguments:
|
|
@verbatim
|
|
void
|
|
InternetStackHelper::Install (Ptr<Node> node) const
|
|
{
|
|
if (node->GetObject<Ipv4> () != 0)
|
|
{
|
|
NS_FATAL_ERROR ("InternetStackHelper::Install(): Aggregating "
|
|
"an InternetStack to a node with an existing Ipv4 object");
|
|
return;
|
|
}
|
|
|
|
CreateAndAggregateObjectFromTypeId (node, "ns3::ArpL3Protocol");
|
|
CreateAndAggregateObjectFromTypeId (node, "ns3::Ipv4L3Protocol");
|
|
CreateAndAggregateObjectFromTypeId (node, "ns3::Icmpv4L4Protocol");
|
|
CreateAndAggregateObjectFromTypeId (node, "ns3::UdpL4Protocol");
|
|
node->AggregateObject (m_tcpFactory.Create<Object> ());
|
|
Ptr<PacketSocketFactory> factory = CreateObject<PacketSocketFactory> ();
|
|
node->AggregateObject (factory);
|
|
// Set routing
|
|
Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
|
|
Ptr<Ipv4RoutingProtocol> ipv4Routing = m_routing->Create (node);
|
|
ipv4->SetRoutingProtocol (ipv4Routing);
|
|
}
|
|
@end verbatim
|
|
|
|
Note that the Ipv4 routing protocol is configured and set outside this
|
|
function. By default, the following protocols are added to Ipv4:
|
|
@verbatim
|
|
InternetStackHelper::InternetStackHelper ()
|
|
{
|
|
SetTcp ("ns3::TcpL4Protocol");
|
|
static Ipv4StaticRoutingHelper staticRouting;
|
|
static Ipv4GlobalRoutingHelper globalRouting;
|
|
static Ipv4ListRoutingHelper listRouting;
|
|
listRouting.Add (staticRouting, 0);
|
|
listRouting.Add (globalRouting, -10);
|
|
SetRoutingHelper (listRouting);
|
|
}
|
|
@end verbatim
|
|
|
|
@subsection Internet Node structure
|
|
|
|
An IPv4-capable Node (an ns-3 Node augmented by aggregation to have one or more
|
|
IP stacks) has the following internal structure.
|
|
|
|
@subsubsection Layer-3 protocols
|
|
At the lowest layer, sitting above the NetDevices, are the "layer 3"
|
|
protocols, including IPv4, IPv6 (in the future), and ARP. The
|
|
@code{class Ipv4L3Protocol} is an
|
|
implementation class whose public interface is
|
|
typically @code{class Ipv4} (found in src/node directory), but the
|
|
Ipv4L3Protocol public API is also used internally in the
|
|
src/internet-stack directory at present.
|
|
|
|
In class Ipv4L3Protocol, one method described below is @code{Receive ()}:
|
|
@verbatim
|
|
/**
|
|
* Lower layer calls this method after calling L3Demux::Lookup
|
|
* The ARP subclass needs to know from which NetDevice this
|
|
* packet is coming to:
|
|
* - implement a per-NetDevice ARP cache
|
|
* - send back arp replies on the right device
|
|
*/
|
|
void Receive( Ptr<NetDevice> device, Ptr<const Packet> p, uint16_t protocol, const Address &from,
|
|
const Address &to, NetDevice::PacketType packetType);
|
|
@end verbatim
|
|
|
|
First, note that the @code{Receive ()} function has a matching signature
|
|
to the ReceiveCallback in the @code{class Node}. This function pointer
|
|
is inserted into the Node's protocol handler when
|
|
@code{AddInterface ()} is called. The actual registration is done
|
|
with a statement such as:
|
|
follows:
|
|
@verbatim
|
|
RegisterProtocolHandler ( MakeCallback (&Ipv4Protocol::Receive, ipv4),
|
|
Ipv4L3Protocol::PROT_NUMBER, 0);
|
|
@end verbatim
|
|
|
|
The Ipv4L3Protocol object is aggregated to the Node; there is only one
|
|
such Ipv4L3Protocol object. Higher-layer protocols that have a packet
|
|
to send down to the Ipv4L3Protocol object can call
|
|
@code{GetObject<Ipv4L3Protocol> ()} to obtain a pointer, as follows:
|
|
@verbatim
|
|
Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
|
|
if (ipv4 != 0)
|
|
{
|
|
ipv4->Send (packet, saddr, daddr, PROT_NUMBER);
|
|
}
|
|
@end verbatim
|
|
|
|
This class nicely demonstrates two techniques we exploit in
|
|
ns-3 to bind objects together: callbacks, and object aggregation.
|
|
|
|
Once IPv4 routing has determined that a packet is for the local node, it
|
|
forwards it up the stack. This is done with the following function:
|
|
|
|
@verbatim
|
|
void
|
|
Ipv4L3Protocol::LocalDeliver (Ptr<const Packet> packet, Ipv4Header const&ip, uint32_t iif)
|
|
@end verbatim
|
|
|
|
The first step is to find the right Ipv4L4Protocol object , based on IP protocol
|
|
number. For instance, TCP is registered in the demux as protocol number 6.
|
|
Finally, the @code{Receive()} function on the Ipv4L4Protocol (such as
|
|
@code{TcpL4Protocol::Receive} is called.
|
|
|
|
We have not yet introduced the class Ipv4Interface. Basically,
|
|
each NetDevice is paired with an IPv4 representation of such device.
|
|
In Linux, this @code{class Ipv4Interface} roughly corresponds to
|
|
the @code{struct in_device}; the main purpose is to provide
|
|
address-family specific information (addresses) about an interface.
|
|
|
|
@subsubsection Layer-4 protocols and sockets
|
|
|
|
We next describe how the transport protocols, sockets, and applications
|
|
tie together. In summary, each transport protocol implementation is
|
|
a socket factory. An application that needs a new socket
|
|
|
|
For instance, to create a UDP socket, an application would use a code
|
|
snippet such as the following:
|
|
@verbatim
|
|
Ptr<Udp> udpSocketFactory = GetNode ()->GetObject<Udp> ();
|
|
Ptr<Socket> m_socket = socketFactory->CreateSocket ();
|
|
m_socket->Bind (m_local_address);
|
|
...
|
|
@end verbatim
|
|
The above will query the node to get a pointer to its UDP socket
|
|
factory, will create one such socket, and will use the socket with
|
|
an API similar to the C-based sockets API, such as @code{Connect ()}
|
|
and @code{Send ()}. See the chapter on ns-3 sockets for more information.
|
|
|
|
We have described so far a socket factory (e.g. @code{class Udp}) and
|
|
a socket, which may be specialized (e.g., @code{class UdpSocket}).
|
|
There are a few more key objects that relate to the specialized
|
|
task of demultiplexing a packet to one or more receiving sockets.
|
|
The key object in this task is @code{class Ipv4EndPointDemux}.
|
|
This demultiplexer stores objects of @code{class Ipv4EndPoint}.
|
|
This class holds the addressing/port tuple (local port, local address,
|
|
destination port, destination address) associated with the socket,
|
|
and a receive callback. This receive callback has a receive
|
|
function registered by the socket. The @code{Lookup ()} function to
|
|
Ipv4EndPointDemux returns a list of Ipv4EndPoint objects (there may
|
|
be a list since more than one socket may match the packet). The
|
|
layer-4 protocol copies the packet to each Ipv4EndPoint and calls
|
|
its @code{ForwardUp ()} method, which then calls the @code{Receive ()}
|
|
function registered by the socket.
|
|
|
|
An issue that arises when working with the sockets API on real
|
|
systems is the need to manage the reading from a socket, using
|
|
some type of I/O (e.g., blocking, non-blocking, asynchronous, ...).
|
|
ns-3 implements an asynchronous model for socket I/O; the application
|
|
sets a callback to be notified of received data ready to be read, and the
|
|
callback is invoked by the transport protocol when data is available.
|
|
This callback is specified as follows:
|
|
@verbatim
|
|
void Socket::SetRecvCallback (Callback<void, Ptr<Socket>,
|
|
Ptr<Packet>, const Address&> receivedData);
|
|
@end verbatim
|
|
The data being received is conveyed in the Packet data buffer. An example
|
|
usage is in @code{class PacketSink}:
|
|
@verbatim
|
|
m_socket->SetRecvCallback (MakeCallback(&PacketSink::HandleRead, this));
|
|
@end verbatim
|
|
|
|
To summarize, internally, the UDP implementation is organized as follows:
|
|
@itemize @bullet
|
|
@item a @code{UdpImpl} class that implements the UDP socket factory
|
|
functionality
|
|
@item a @code{UdpL4Protocol} class that implements the protocol logic
|
|
that is socket-independent
|
|
@item a @code{UdpSocketImpl} class that implements socket-specific aspects
|
|
of UDP
|
|
@item a class called @code{Ipv4EndPoint} that stores the
|
|
addressing tuple (local port, local address, destination port, destination
|
|
address) associated with the socket, and a receive callback for the socket.
|
|
@end itemize
|
|
|
|
@subsection Ipv4-capable node interfaces
|
|
|
|
Many of the implementation details, or internal objects themselves,
|
|
of Ipv4-capable Node objects are not exposed at the simulator public
|
|
API. This allows for different implementations; for instance,
|
|
replacing the native ns-3 models with ported TCP/IP stack code.
|
|
|
|
The C++ public APIs of all of these objects is found in the
|
|
@code{src/node} directory, including principally:
|
|
@itemize @bullet
|
|
@item @code{socket.h}
|
|
@item @code{tcp.h}
|
|
@item @code{udp.h}
|
|
@item @code{ipv4.h}
|
|
@end itemize
|
|
These are typically base class objects that implement the default
|
|
values used in the implementation, implement access methods to get/set
|
|
state variables, host attributes, and implement publicly-available methods
|
|
exposed to clients such as @code{CreateSocket}.
|
|
|
|
@subsection Example path of a packet
|
|
|
|
These two figures show an example stack trace of how packets flow
|
|
through the Internet Node objects.
|
|
|
|
@float Figure,fig:internet-node-send
|
|
@caption{Send path of a packet.}
|
|
@image{figures/internet-node-send,5in}
|
|
@end float
|
|
|
|
@float Figure,fig:internet-node-recv
|
|
@caption{Receive path of a packet.}
|
|
@image{figures/internet-node-recv,5in}
|
|
@end float
|
|
|