traffic-control: Add the traffic control layer

This commit is contained in:
Natale Patriciello
2016-03-08 10:43:16 -08:00
parent 5ef77015d8
commit 37af8b51de
9 changed files with 453 additions and 0 deletions

View File

@@ -55,6 +55,7 @@
* - spectrum
* - stats
* - tap-bridge
* - traffic-control
* - test
* - topology-read
* - uan

View File

@@ -17,6 +17,7 @@ SOURCES = \
source/internet-models.rst \
source/network.rst \
source/emulation-overview.rst \
source/traffic-control.rst \
$(SRC)/antenna/doc/source/antenna.rst \
$(SRC)/antenna/doc/source/antenna-design.rst \
$(SRC)/antenna/doc/source/antenna-user.rst \
@@ -75,6 +76,7 @@ SOURCES = \
$(SRC)/wimax/doc/wimax.rst \
$(SRC)/uan/doc/uan.rst \
$(SRC)/topology-read/doc/topology.rst \
$(SRC)/traffic-control/doc/traffic-control-layer.rst \
$(SRC)/spectrum/doc/spectrum.rst \
$(SRC)/stats/doc/adaptor.rst \
$(SRC)/stats/doc/aggregator.rst \

View File

@@ -47,6 +47,7 @@ This document is written in `reStructuredText <http://docutils.sourceforge.net/r
spectrum
sixlowpan
topology
traffic-control
uan
wave
wifi

View File

@@ -0,0 +1,6 @@
Traffic Control Layer
---------------------------------------------------------------------
.. toctree::
traffic-control-layer

View File

@@ -0,0 +1,127 @@
Traffic Control Layer
---------------------
.. heading hierarchy:
------------- Chapter
************* Section (#.#)
============= Subsection (#.#.#)
############# Paragraph (no number)
The Traffic Control layer aims at introducing an equivalent of the Linux Traffic
Control infrastructure into ns-3. The Traffic Control layer sits in between
the NetDevices (L2) and any network protocol (e.g. IP). It is in charge of processing
packets and performing actions on them: scheduling, dropping, marking, policing, etc.
Introducing the Traffic Control Layer
*************************************
The Traffic Control layer intercepts both outgoing packets flowing downwards from
the network layer to the network device and incoming packets flowing in the opposite
direction. Currently, only outgoing packets are processed by the Traffic Control layer.
In particular, outgoing packets are enqueued in a queuing discipline, which can perform
multiple actions on them.
In the following, more details are given about how the Traffic Control layer intercepts
outgoing and incoming packets and, more in general, about how the packets traverse the
network stack.
Transmitting packets
====================
The IPv{4,6} interfaces uses the aggregated object TrafficControlLayer to send
down packets, instead of calling NetDevice::Send() directly. After the analysis
and the process of the packet, when the backpressure mechanism allows it,
TrafficControlLayer will call the Send() method on the right NetDevice.
Receiving packets
=================
The callback chain that (in the past) involved IPv{4,6}L3Protocol and NetDevices,
through ReceiveCallback, is extended to involve TrafficControlLayer. When an
IPv{4,6}Interface is added in the IPv{4,6}L3Protocol, the callback chain is
configured to have the following packet exchange:
NetDevice --> Node --> TrafficControlLayer --> IPv{4,6}L3Protocol
Brief description of old node/device/protocol interactions
**************************************************************
The main question that we would like to answer in the following paragraphs is:
how a ns-3 node can send/receive packets?
If we analyze any example out there, the ability of the node to receive/transmit
packets derives from the interaction of two helper:
* L2 Helper (something derived from NetDevice)
* L3 Helper (usually from Internet module)
L2 Helper main operations
=========================
Any good L2 Helper will do the following operations:
* Create n netdevices (n>1)
* Attach a channel between these devices
* Call Node::AddDevice ()
Obviously the last point is the most important.
Node::AddDevice (network/model/node.cc:128) assigns an interface index to the
device, calls NetDevice::SetNode, sets the receive callback of the device to
Node::NonPromiscReceiveFromDevice. Then, it schedules NetDevice::Initialize() method at
Seconds(0.0), then notify the registered DeviceAdditionListener handlers (not used BY ANYONE).
Node::NonPromiscReceiveFromDevice calls Node::ReceiveFromDevice.
Node::ReceiveFromDevice iterates through ProtocolHandlers, which are callbacks
which accept as signature:
ProtocolHandler (Ptr<NetDevice>, Ptr<const Packet>, protocol, from_addr, to_addr, packetType).
If device, protocol number and promiscuous flag corresponds, the handler is
invoked.
Who is responsible to set ProtocolHandler ? We will analyze that in the next
section.
L3 Helper
=========
We have only internet which provides network protocol (IP). That module splits
the operations between two helpers: InternetStackHelper and Ipv{4,6}AddressHelper.
InternetStackHelper::Install (internet/helper/internet-stack-helper.cc:423)
creates and aggregates protocols {ArpL3,Ipv4L3,Icmpv4}Protocol. It creates the
routing protocol, and if Ipv6 is enabled it adds {Ipv6L3,Icmpv6L4}Protocol. In
any case, it instantiates and aggregates an UdpL4Protocol object, along with a
PacketSocketFactory.
Ultimately, it creates the required objects and aggregates them to the node.
Let's assume an Ipv4 environment (things are the same for Ipv6).
Ipv4AddressHelper::Assign (src/internet/helper/ipv4-address-helper.cc:131)
registers the handlers. The process is a bit long. The method is called with
a list of NetDevice. For each of them, the node and Ipv4L3Protocol pointers are
retrieved; if an Ipv4Interface is already registered for the device, on that the
address is set. Otherwise, the method Ipv4L3Protocol::AddInterface is called,
before adding the address.
IP interfaces
=============
In Ipv4L3Protocol::AddInterface (src/internet/model/ipv4-l3-protocol.cc:300)
two protocol handlers are installed: one that react to ipv4 protocol number,
and one that react to arp protocol number (Ipv4L3Protocol::Receive and
ArpL3Protocol::Receive, respectively). The interface is then created,
initialized, and returned.
Ipv4L3Protocol::Receive (src/internet/model/ipv4-l3-protocol.cc:472) iterates
through the interface. Once it finds the Ipv4Interface which has the same device
as the one passed as argument, invokes the rxTrace callback. If the interface is
down, the packet is dropped. Then, it removes the header and trim any residual
frame padding. If checksum is not OK, it drops the packet. Otherwise, forward
the packet to the raw sockets (not used). Then, it ask the routing protocol what
is the destiny of that packet. The choices are: Ipv4L3Protocol::{IpForward,
IpMulticastForward,LocalDeliver,RouteInputError}.

View File

@@ -0,0 +1,7 @@
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
def build(bld):
pass
# obj = bld.create_ns3_program('traffic-control-example', ['traffic-control'])
# obj.source = 'traffic-control-example.cc'

View File

@@ -0,0 +1,116 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2015 Natale Patriciello <natale.patriciello@gmail.com>
*
* 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
*/
#include "traffic-control-layer.h"
#include "ns3/log.h"
#include "ns3/packet.h"
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("TrafficControlLayer");
NS_OBJECT_ENSURE_REGISTERED (TrafficControlLayer);
TypeId
TrafficControlLayer::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::TrafficControlLayer")
.SetParent<Object> ()
.SetGroupName ("TrafficControl")
.AddConstructor<TrafficControlLayer> ()
;
return tid;
}
TypeId
TrafficControlLayer::GetInstanceTypeId (void) const
{
return GetTypeId ();
}
TrafficControlLayer::TrafficControlLayer ()
: Object ()
{
NS_LOG_FUNCTION_NOARGS ();
}
void
TrafficControlLayer::RegisterProtocolHandler (Node::ProtocolHandler handler,
uint16_t protocolType, Ptr<NetDevice> device)
{
NS_LOG_FUNCTION (this << protocolType << device);
struct ProtocolHandlerEntry entry;
entry.handler = handler;
entry.protocol = protocolType;
entry.device = device;
entry.promiscuous = false;
m_handlers.push_back (entry);
NS_LOG_DEBUG ("Handler for NetDevice: " << device << " registered for protocol " <<
protocolType << ".");
}
void
TrafficControlLayer::Receive (Ptr<NetDevice> device, Ptr<const Packet> p,
uint16_t protocol, const Address &from, const Address &to,
NetDevice::PacketType packetType)
{
NS_LOG_FUNCTION (this << device << p << protocol << from << to << packetType);
bool found = false;
for (ProtocolHandlerList::iterator i = m_handlers.begin ();
i != m_handlers.end (); i++)
{
if (i->device == 0
|| (i->device != 0 && i->device == device))
{
if (i->protocol == 0
|| i->protocol == protocol)
{
NS_LOG_DEBUG ("Found handler for packet " << p << ", protocol " <<
protocol << " and NetDevice " << device <<
". Send packet up");
i->handler (device, p, protocol, from, to, packetType);
found = true;
}
}
}
if (! found)
{
NS_FATAL_ERROR ("Handler for protocol " << p << " and device " << device <<
" not found. It isn't forwarded up; it dies here.");
}
}
void
TrafficControlLayer::Send (Ptr<NetDevice> device, Ptr<Packet> packet,
const Address &dest, uint16_t protocolNumber)
{
NS_LOG_FUNCTION (this << device << packet << dest << protocolNumber);
NS_LOG_DEBUG ("Send packet to device " << device << " protocol number " <<
protocolNumber);
device->Send (packet, dest, protocolNumber);
}
} // namespace ns3

View File

@@ -0,0 +1,164 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2015 Natale Patriciello <natale.patriciello@gmail.com>
*
* 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
*/
#ifndef TRAFFICCONTROLLAYER_H
#define TRAFFICCONTROLLAYER_H
#include "ns3/object.h"
#include "ns3/address.h"
#include "ns3/net-device.h"
#include "ns3/node.h"
namespace ns3 {
class Packet;
/**
* \brief Traffic control layer definition
*
* This layer stays between NetDevices (L2) and any network protocol (e.g. IP).
* When enabled, it is responsible to analyze packets and to perform actions on
* them: the most common is scheduling.
*
* Basically, we manage both IN and OUT directions (sometimes called RX and TX,
* respectively). The OUT direction is easy to follow, since it involves
* direct calls: upper layer (e.g. IP) calls the Send method on an instance of
* this class, which then call the Send method of some NetDevice.
*
* The IN direction uses a little trick to reduce dependencies between modules.
* In simple words, we use Callbacks to connect upper layer (which should register
* their Receive callback through RegisterProtocolHandler) and NetDevices.
*
* An example of the IN connection between this layer and IP layer is the following:
*\verbatim
Ptr<TrafficControlLayer> tc = m_node->GetObject<TrafficControlLayer> ();
NS_ASSERT (tc != 0);
m_node->RegisterProtocolHandler (MakeCallback (&TrafficControlLayer::Receive, tc),
Ipv4L3Protocol::PROT_NUMBER, device);
m_node->RegisterProtocolHandler (MakeCallback (&TrafficControlLayer::Receive, tc),
ArpL3Protocol::PROT_NUMBER, device);
tc->RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, this),
Ipv4L3Protocol::PROT_NUMBER, device);
tc->RegisterProtocolHandler (MakeCallback (&ArpL3Protocol::Receive, PeekPointer (GetObject<ArpL3Protocol> ())),
ArpL3Protocol::PROT_NUMBER, device);
\endverbatim
* On the node, for IPv4 and ARP packet, is registered the
* TrafficControlLayer::Receive callback. At the same time, on the TrafficControlLayer
* object, is registered the callbacks associated to the upper layers (IPv4 or ARP).
*
* When the node receives an IPv4 or ARP packet, it calls the Receive method
* on TrafficControlLayer, that calls the right upper-layer callback once it
* finishes the operations on the packet received.
*
* Discrimination through callbacks (in other words: what is the right upper-layer
* callback for this packet?) is done through checks over the device and the
* protocol number.
*/
class TrafficControlLayer : public Object
{
public:
/**
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId (void);
/**
* \brief Get the type ID for the instance
* \return the instance TypeId
*/
virtual TypeId GetInstanceTypeId (void) const;
/**
* \brief Constructor
*/
TrafficControlLayer ();
/**
* \brief Register an IN handler
*
* The handler will be invoked when a packet is received to pass it to
* upper layers.
*
* \param handler the handler to register
* \param protocolType the type of protocol this handler is
* interested in. This protocol type is a so-called
* EtherType, as registered here:
* http://standards.ieee.org/regauth/ethertype/eth.txt
* the value zero is interpreted as matching all
* protocols.
* \param device the device attached to this handler. If the
* value is zero, the handler is attached to all
* devices.
*/
void RegisterProtocolHandler (Node::ProtocolHandler handler,
uint16_t protocolType,
Ptr<NetDevice> device);
/**
* \brief Called by NetDevices, incoming packet
*
* After analyses and scheduling, this method will call the right handler
* to pass the packet up in the stack.
*
* \param device network device
* \param p the packet
* \param protocol next header value
* \param from address of the correspondant
* \param to address of the destination
* \param packetType type of the packet
*/
virtual void Receive (Ptr<NetDevice> device, Ptr<const Packet> p,
uint16_t protocol, const Address &from,
const Address &to, NetDevice::PacketType packetType);
/**
* \brief Called from upper layer to queue a packet for the transmission.
*
* \param packet packet sent from above
* \param dest mac address of the destination (already resolved)
* \param protocolNumber identifies the type of payload contained in
* this packet. Used to call the right L3Protocol when the packet
* is received.
*
*/
virtual void Send (Ptr<NetDevice> device, Ptr<Packet> packet,
const Address& dest, uint16_t protocolNumber);
private:
/**
* \brief Protocol handler entry.
* This structure is used to demultiplex all the protocols.
*/
struct ProtocolHandlerEntry {
Node::ProtocolHandler handler; //!< the protocol handler
Ptr<NetDevice> device; //!< the NetDevice
uint16_t protocol; //!< the protocol number
bool promiscuous; //!< true if it is a promiscuous handler
};
/// Typedef for protocol handlers container
typedef std::vector<struct ProtocolHandlerEntry> ProtocolHandlerList;
ProtocolHandlerList m_handlers; //!< List of upper-layer handlers
};
} // namespace ns3
#endif // TRAFFICCONTROLLAYER_H

View File

@@ -0,0 +1,29 @@
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
# def options(opt):
# pass
# def configure(conf):
# conf.check_nonfatal(header_name='stdint.h', define_name='HAVE_STDINT_H')
def build(bld):
module = bld.create_ns3_module('traffic-control', ['core'])
module.source = [
'model/traffic-control-layer.cc'
]
module_test = bld.create_ns3_module_test_library('traffic-control')
module_test.source = [
]
headers = bld(features='ns3header')
headers.module = 'traffic-control'
headers.source = [
'model/traffic-control-layer.h'
]
if bld.env.ENABLE_EXAMPLES:
bld.recurse('examples')
# bld.ns3_python_bindings()