From 37af8b51de7263e56c731a050ebc6d6cc924191f Mon Sep 17 00:00:00 2001 From: Natale Patriciello Date: Tue, 8 Mar 2016 10:43:16 -0800 Subject: [PATCH] traffic-control: Add the traffic control layer --- doc/main.h | 1 + doc/models/Makefile | 2 + doc/models/source/index.rst | 1 + doc/models/source/traffic-control.rst | 6 + .../doc/traffic-control-layer.rst | 127 ++++++++++++++ src/traffic-control/examples/wscript | 7 + .../model/traffic-control-layer.cc | 116 +++++++++++++ .../model/traffic-control-layer.h | 164 ++++++++++++++++++ src/traffic-control/wscript | 29 ++++ 9 files changed, 453 insertions(+) create mode 100644 doc/models/source/traffic-control.rst create mode 100644 src/traffic-control/doc/traffic-control-layer.rst create mode 100644 src/traffic-control/examples/wscript create mode 100644 src/traffic-control/model/traffic-control-layer.cc create mode 100644 src/traffic-control/model/traffic-control-layer.h create mode 100644 src/traffic-control/wscript diff --git a/doc/main.h b/doc/main.h index 87edca040..92f13a53d 100644 --- a/doc/main.h +++ b/doc/main.h @@ -55,6 +55,7 @@ * - spectrum * - stats * - tap-bridge + * - traffic-control * - test * - topology-read * - uan diff --git a/doc/models/Makefile b/doc/models/Makefile index 5a2e33a1a..47a06b47f 100644 --- a/doc/models/Makefile +++ b/doc/models/Makefile @@ -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 \ diff --git a/doc/models/source/index.rst b/doc/models/source/index.rst index 184f9779a..f7d12aeb3 100644 --- a/doc/models/source/index.rst +++ b/doc/models/source/index.rst @@ -47,6 +47,7 @@ This document is written in `reStructuredText 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, Ptr, 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}. + diff --git a/src/traffic-control/examples/wscript b/src/traffic-control/examples/wscript new file mode 100644 index 000000000..6c879c3b8 --- /dev/null +++ b/src/traffic-control/examples/wscript @@ -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' + diff --git a/src/traffic-control/model/traffic-control-layer.cc b/src/traffic-control/model/traffic-control-layer.cc new file mode 100644 index 000000000..36db69ec2 --- /dev/null +++ b/src/traffic-control/model/traffic-control-layer.cc @@ -0,0 +1,116 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2015 Natale Patriciello + * + * 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 () + .SetGroupName ("TrafficControl") + .AddConstructor () + ; + 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 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 device, Ptr 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 device, Ptr 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 diff --git a/src/traffic-control/model/traffic-control-layer.h b/src/traffic-control/model/traffic-control-layer.h new file mode 100644 index 000000000..2dd68bf18 --- /dev/null +++ b/src/traffic-control/model/traffic-control-layer.h @@ -0,0 +1,164 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2015 Natale Patriciello + * + * 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 tc = m_node->GetObject (); + + 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::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 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 device, Ptr 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 device, Ptr 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 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 ProtocolHandlerList; + + ProtocolHandlerList m_handlers; //!< List of upper-layer handlers +}; + +} // namespace ns3 + +#endif // TRAFFICCONTROLLAYER_H diff --git a/src/traffic-control/wscript b/src/traffic-control/wscript new file mode 100644 index 000000000..2cef94b37 --- /dev/null +++ b/src/traffic-control/wscript @@ -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() +