diff --git a/doc/main.h b/doc/main.h index 87edca04077..92f13a53dfd 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 a2278a6639c..301058db874 100644 --- a/doc/models/Makefile +++ b/doc/models/Makefile @@ -75,6 +75,7 @@ SOURCES = \ $(SRC)/wimax/doc/wimax.rst \ $(SRC)/uan/doc/uan.rst \ $(SRC)/topology-read/doc/topology.rst \ + $(SRC)/traffic-control/doc/traffic-control.rst \ $(SRC)/spectrum/doc/spectrum.rst \ $(SRC)/stats/doc/adaptor.rst \ $(SRC)/stats/doc/aggregator.rst \ @@ -262,6 +263,8 @@ SOURCEFIGS = \ $(SRC)/spectrum/doc/spectrum-tv-rand-geo-points.eps \ $(SRC)/spectrum/doc/spectrum-tv-8vsb.png \ $(SRC)/spectrum/doc/spectrum-tv-cofdm.png \ + $(SRC)/traffic-control/doc/root-queue-disc.dia \ + $(SRC)/traffic-control/doc/child-queue-discs.dia \ $(SRC)/lr-wpan/doc/lr-wpan-arch.dia \ $(SRC)/lr-wpan/doc/lr-wpan-data-example.dia \ $(SRC)/lr-wpan/doc/lr-wpan-primitives.dia \ @@ -348,6 +351,8 @@ IMAGES_EPS = \ $(FIGURES)/auvmobility-classes.eps \ $(FIGURES)/spectrum-analyzer-example.eps \ $(FIGURES)/spectrum-tv-rand-geo-points.eps \ + $(FIGURES)/root-queue-disc.eps \ + $(FIGURES)/child-queue-discs.eps \ $(FIGURES)/lr-wpan-primitives.eps \ $(FIGURES)/lr-wpan-data-example.eps \ $(FIGURES)/lr-wpan-arch.eps \ diff --git a/doc/models/source/index.rst b/doc/models/source/index.rst index 184f9779a71..f7d12aeb349 100644 --- a/doc/models/source/index.rst +++ b/doc/models/source/index.rst @@ -47,6 +47,7 @@ This document is written in `reStructuredText + * Author: Stefano Avallone + */ + +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/internet-module.h" +#include "ns3/point-to-point-module.h" +#include "ns3/applications-module.h" +#include "ns3/traffic-control-module.h" + +// This simple example shows how to use TrafficContorlHelper to install a QueueDisc on a device. +// The default QueueDisc is a pfifo_fast with max number of packets equal to 1000 (as in Linux) +// +// Network topology +// +// 10.1.1.0 +// n0 -------------- n1 +// point-to-point + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("TrafficControlExample"); + +void +PacketsInQueueTrace (uint32_t oldValue, uint32_t newValue) +{ + std::cout << "PacketsInQueue " << oldValue << " to " << newValue << std::endl; +} + +int +main (int argc, char *argv[]) +{ + double simulationTime = 10; //seconds + + NodeContainer nodes; + nodes.Create (2); + + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("10Mbps")); + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); + pointToPoint.SetQueue ("ns3::DropTailQueue", "Mode", StringValue ("QUEUE_MODE_PACKETS"), "MaxPackets", UintegerValue (1000)); + + NetDeviceContainer devices; + devices = pointToPoint.Install (nodes); + + InternetStackHelper stack; + stack.Install (nodes); + + QueueDiscHelper qdh; + qdh.SetQueueDiscType ("ns3::PfifoFastQueueDisc"); + qdh.SetAttribute ("Band0", PointerValue (CreateObjectWithAttributes ("MaxPackets", UintegerValue (1000)))); + qdh.SetAttribute ("Band1", PointerValue (CreateObjectWithAttributes ("MaxPackets", UintegerValue (1000)))); + qdh.SetAttribute ("Band2", PointerValue (CreateObjectWithAttributes ("MaxPackets", UintegerValue (1000)))); + QueueDiscContainer qdiscs = qdh.Install (devices); + + Ptr q = qdiscs.Get (0); + q->TraceConnectWithoutContext ("PacketsInQueue", MakeCallback (&PacketsInQueueTrace)); + + Ipv4AddressHelper address; + address.SetBase ("10.1.1.0", "255.255.255.0"); + + Ipv4InterfaceContainer interfaces = address.Assign (devices); + + //Flow + uint16_t port = 7; + Address localAddress (InetSocketAddress (Ipv4Address::GetAny (), port)); + PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", localAddress); + ApplicationContainer sinkApp = packetSinkHelper.Install (nodes.Get (0)); + + sinkApp.Start (Seconds (0.0)); + sinkApp.Stop (Seconds (simulationTime + 0.1)); + + uint32_t payloadSize = 1448; + Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (payloadSize)); + + OnOffHelper onoff ("ns3::TcpSocketFactory",Ipv4Address::GetAny ()); + onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); + onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); + onoff.SetAttribute ("PacketSize", UintegerValue (payloadSize)); + onoff.SetAttribute ("DataRate", DataRateValue (1000000000)); //bit/s + ApplicationContainer apps; + + AddressValue remoteAddress (InetSocketAddress (interfaces.GetAddress (0), port)); + onoff.SetAttribute ("Remote", remoteAddress); + apps.Add (onoff.Install (nodes.Get (1))); + apps.Start (Seconds (1.0)); + apps.Stop (Seconds (simulationTime + 0.1)); + + Simulator::Stop (Seconds (simulationTime + 0.1)); + Simulator::Run (); + Simulator::Destroy (); + + double thr = 0; + uint32_t totalPacketsThr = DynamicCast (sinkApp.Get (0))->GetTotalRx (); + thr = totalPacketsThr * 8 / (simulationTime * 1000000.0); //Mbit/s + std::cout << thr << " Mbit/s" <Dequeue (); - NS_ASSERT_MSG (m_currentPkt != 0, "CsmaNetDevice::TransmitAbort(): IsEmpty false but no Packet on queue?"); + Ptr item = m_queue->Dequeue (); + NS_ASSERT_MSG (item != 0, "CsmaNetDevice::TransmitAbort(): IsEmpty false but no Packet on queue?"); + m_currentPkt = item->GetPacket (); m_snifferTrace (m_currentPkt); m_promiscSnifferTrace (m_currentPkt); TransmitStart (); @@ -632,8 +633,9 @@ CsmaNetDevice::TransmitReadyEvent (void) } else { - m_currentPkt = m_queue->Dequeue (); - NS_ASSERT_MSG (m_currentPkt != 0, "CsmaNetDevice::TransmitReadyEvent(): IsEmpty false but no Packet on queue?"); + Ptr item = m_queue->Dequeue (); + NS_ASSERT_MSG (item != 0, "CsmaNetDevice::TransmitReadyEvent(): IsEmpty false but no Packet on queue?"); + m_currentPkt = item->GetPacket (); m_snifferTrace (m_currentPkt); m_promiscSnifferTrace (m_currentPkt); TransmitStart (); @@ -968,7 +970,7 @@ CsmaNetDevice::SendFrom (Ptr packet, const Address& src, const Address& // Place the packet to be sent on the send queue. Note that the // queue may fire a drop trace, but we will too. // - if (m_queue->Enqueue (packet) == false) + if (m_queue->Enqueue (Create (packet)) == false) { m_macTxDropTrace (packet); return false; @@ -983,8 +985,9 @@ CsmaNetDevice::SendFrom (Ptr packet, const Address& src, const Address& { if (m_queue->IsEmpty () == false) { - m_currentPkt = m_queue->Dequeue (); - NS_ASSERT_MSG (m_currentPkt != 0, "CsmaNetDevice::SendFrom(): IsEmpty false but no Packet on queue?"); + Ptr item = m_queue->Dequeue (); + NS_ASSERT_MSG (item != 0, "CsmaNetDevice::SendFrom(): IsEmpty false but no Packet on queue?"); + m_currentPkt = item->GetPacket (); m_promiscSnifferTrace (m_currentPkt); m_snifferTrace (m_currentPkt); TransmitStart (); diff --git a/src/internet/helper/internet-stack-helper.cc b/src/internet/helper/internet-stack-helper.cc index d7993bb3158..0669c4cd853 100644 --- a/src/internet/helper/internet-stack-helper.cc +++ b/src/internet/helper/internet-stack-helper.cc @@ -175,6 +175,7 @@ #include "ns3/ipv6-extension-header.h" #include "ns3/icmpv6-l4-protocol.h" #include "ns3/global-router-interface.h" +#include "ns3/traffic-control-layer.h" #include #include @@ -473,6 +474,7 @@ InternetStackHelper::Install (Ptr node) const if (m_ipv4Enabled || m_ipv6Enabled) { + CreateAndAggregateObjectFromTypeId (node, "ns3::TrafficControlLayer"); CreateAndAggregateObjectFromTypeId (node, "ns3::UdpL4Protocol"); node->AggregateObject (m_tcpFactory.Create ()); Ptr factory = CreateObject (); @@ -489,12 +491,13 @@ InternetStackHelper::Install (std::string nodeName) const /** * \brief Sync function for IPv4 packet - Pcap output + * \param header IPv4 header * \param p smart pointer to the packet * \param ipv4 smart pointer to the node's IPv4 stack * \param interface incoming interface */ static void -Ipv4L3ProtocolRxTxSink (Ptr p, Ptr ipv4, uint32_t interface) +Ipv4L3ProtocolRxTxSink (Ipv4Header const &header, Ptr p, Ptr ipv4, uint32_t interface) { NS_LOG_FUNCTION (p << ipv4 << interface); @@ -512,7 +515,7 @@ Ipv4L3ProtocolRxTxSink (Ptr p, Ptr ipv4, uint32_t interface) } Ptr file = g_interfaceFileMapIpv4[pair]; - file->Write (Simulator::Now (), p); + file->Write (Simulator::Now (), header, p); } bool @@ -587,12 +590,13 @@ InternetStackHelper::EnablePcapIpv4Internal (std::string prefix, Ptr ipv4, /** * \brief Sync function for IPv6 packet - Pcap output + * \param header IPv6 header * \param p smart pointer to the packet * \param ipv6 smart pointer to the node's IPv6 stack * \param interface incoming interface */ static void -Ipv6L3ProtocolRxTxSink (Ptr p, Ptr ipv6, uint32_t interface) +Ipv6L3ProtocolRxTxSink (Ipv6Header const &header, Ptr p, Ptr ipv6, uint32_t interface) { NS_LOG_FUNCTION (p << ipv6 << interface); @@ -610,7 +614,7 @@ Ipv6L3ProtocolRxTxSink (Ptr p, Ptr ipv6, uint32_t interface) } Ptr file = g_interfaceFileMapIpv6[pair]; - file->Write (Simulator::Now (), p); + file->Write (Simulator::Now (), header, p); } bool @@ -722,6 +726,7 @@ Ipv4L3ProtocolDropSinkWithoutContext ( /** * \brief Sync function for IPv4 transmitted packet - Ascii output * \param stream the output stream + * \param header IPv4 header * \param packet smart pointer to the packet * \param ipv4 smart pointer to the node's IPv4 stack * \param interface incoming interface @@ -729,6 +734,7 @@ Ipv4L3ProtocolDropSinkWithoutContext ( static void Ipv4L3ProtocolTxSinkWithoutContext ( Ptr stream, + Ipv4Header const &header, Ptr packet, Ptr ipv4, uint32_t interface) @@ -740,12 +746,13 @@ Ipv4L3ProtocolTxSinkWithoutContext ( return; } - *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << *packet << std::endl; + *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << header << *packet << std::endl; } /** * \brief Sync function for IPv4 received packet - Ascii output * \param stream the output stream + * \param header IPv4 header * \param packet smart pointer to the packet * \param ipv4 smart pointer to the node's IPv4 stack * \param interface incoming interface @@ -753,6 +760,7 @@ Ipv4L3ProtocolTxSinkWithoutContext ( static void Ipv4L3ProtocolRxSinkWithoutContext ( Ptr stream, + Ipv4Header const &header, Ptr packet, Ptr ipv4, uint32_t interface) @@ -764,7 +772,7 @@ Ipv4L3ProtocolRxSinkWithoutContext ( return; } - *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << *packet << std::endl; + *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << header << *packet << std::endl; } /** @@ -814,6 +822,7 @@ Ipv4L3ProtocolDropSinkWithContext ( * \brief Sync function for IPv4 transmitted packet - Ascii output * \param stream the output stream * \param context the context + * \param header IPv4 header * \param packet smart pointer to the packet * \param ipv4 smart pointer to the node's IPv4 stack * \param interface incoming interface @@ -822,6 +831,7 @@ static void Ipv4L3ProtocolTxSinkWithContext ( Ptr stream, std::string context, + Ipv4Header const &header, Ptr packet, Ptr ipv4, uint32_t interface) @@ -835,9 +845,10 @@ Ipv4L3ProtocolTxSinkWithContext ( #ifdef INTERFACE_CONTEXT *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") " - << *packet << std::endl; + << header << *packet << std::endl; #else - *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << context << " " << *packet << std::endl; + *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << context << " " + << header << *packet << std::endl; #endif } @@ -845,6 +856,7 @@ Ipv4L3ProtocolTxSinkWithContext ( * \brief Sync function for IPv4 received packet - Ascii output * \param stream the output stream * \param context the context + * \param header IPv4 header * \param packet smart pointer to the packet * \param ipv4 smart pointer to the node's IPv4 stack * \param interface incoming interface @@ -853,6 +865,7 @@ static void Ipv4L3ProtocolRxSinkWithContext ( Ptr stream, std::string context, + Ipv4Header const &header, Ptr packet, Ptr ipv4, uint32_t interface) @@ -866,9 +879,10 @@ Ipv4L3ProtocolRxSinkWithContext ( #ifdef INTERFACE_CONTEXT *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") " - << *packet << std::endl; + << header << *packet << std::endl; #else - *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << context << " " << *packet << std::endl; + *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << context << " " + << header << *packet << std::endl; #endif } @@ -1060,6 +1074,7 @@ Ipv6L3ProtocolDropSinkWithoutContext ( /** * \brief Sync function for IPv6 transmitted packet - Ascii output * \param stream the output stream + * \param header IPv6 header * \param packet smart pointer to the packet * \param ipv6 smart pointer to the node's IPv6 stack * \param interface incoming interface @@ -1067,6 +1082,7 @@ Ipv6L3ProtocolDropSinkWithoutContext ( static void Ipv6L3ProtocolTxSinkWithoutContext ( Ptr stream, + Ipv6Header const &header, Ptr packet, Ptr ipv6, uint32_t interface) @@ -1078,12 +1094,13 @@ Ipv6L3ProtocolTxSinkWithoutContext ( return; } - *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << *packet << std::endl; + *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << header << *packet << std::endl; } /** * \brief Sync function for IPv6 received packet - Ascii output * \param stream the output stream + * \param header IPv6 header * \param packet smart pointer to the packet * \param ipv6 smart pointer to the node's IPv6 stack * \param interface incoming interface @@ -1091,6 +1108,7 @@ Ipv6L3ProtocolTxSinkWithoutContext ( static void Ipv6L3ProtocolRxSinkWithoutContext ( Ptr stream, + Ipv6Header const &header, Ptr packet, Ptr ipv6, uint32_t interface) @@ -1102,7 +1120,7 @@ Ipv6L3ProtocolRxSinkWithoutContext ( return; } - *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << *packet << std::endl; + *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << header << *packet << std::endl; } /** @@ -1152,6 +1170,7 @@ Ipv6L3ProtocolDropSinkWithContext ( * \brief Sync function for IPv6 transmitted packet - Ascii output * \param stream the output stream * \param context the context + * \param header IPv6 header * \param packet smart pointer to the packet * \param ipv6 smart pointer to the node's IPv6 stack * \param interface incoming interface @@ -1160,6 +1179,7 @@ static void Ipv6L3ProtocolTxSinkWithContext ( Ptr stream, std::string context, + Ipv6Header const &header, Ptr packet, Ptr ipv6, uint32_t interface) @@ -1173,9 +1193,9 @@ Ipv6L3ProtocolTxSinkWithContext ( #ifdef INTERFACE_CONTEXT *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") " - << *packet << std::endl; + << header << *packet << std::endl; #else - *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << context << " " << *packet << std::endl; + *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << context << " " << header << *packet << std::endl; #endif } @@ -1183,6 +1203,7 @@ Ipv6L3ProtocolTxSinkWithContext ( * \brief Sync function for IPv6 received packet - Ascii output * \param stream the output stream * \param context the context + * \param header IPv6 header * \param packet smart pointer to the packet * \param ipv6 smart pointer to the node's IPv6 stack * \param interface incoming interface @@ -1191,6 +1212,7 @@ static void Ipv6L3ProtocolRxSinkWithContext ( Ptr stream, std::string context, + Ipv6Header const &header, Ptr packet, Ptr ipv6, uint32_t interface) @@ -1204,9 +1226,9 @@ Ipv6L3ProtocolRxSinkWithContext ( #ifdef INTERFACE_CONTEXT *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") " - << *packet << std::endl; + << header << *packet << std::endl; #else - *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << context << " " << *packet << std::endl; + *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << context << " " << header << *packet << std::endl; #endif } diff --git a/src/internet/model/arp-cache.cc b/src/internet/model/arp-cache.cc index 0d1134a33df..005535f0801 100644 --- a/src/internet/model/arp-cache.cc +++ b/src/internet/model/arp-cache.cc @@ -219,10 +219,10 @@ ArpCache::HandleWaitReplyTimeout (void) entry->GetRetries ()); entry->MarkDead (); entry->ClearRetries (); - Ptr pending = entry->DequeuePending (); - while (pending != 0) + PacketWithHeader pending = entry->DequeuePending (); + while (pending.first != 0) { - m_dropTrace (pending); + m_dropTrace (pending.first); pending = entry->DequeuePending (); } } @@ -399,9 +399,9 @@ ArpCache::Entry::MarkPermanent (void) UpdateSeen (); } bool -ArpCache::Entry::UpdateWaitReply (Ptr waiting) +ArpCache::Entry::UpdateWaitReply (PacketWithHeader waiting) { - NS_LOG_FUNCTION (this << waiting); + NS_LOG_FUNCTION (this << waiting.first); NS_ASSERT (m_state == WAIT_REPLY); /* We are already waiting for an answer so * we dump the previously waiting packet and @@ -415,9 +415,9 @@ ArpCache::Entry::UpdateWaitReply (Ptr waiting) return true; } void -ArpCache::Entry::MarkWaitReply (Ptr waiting) +ArpCache::Entry::MarkWaitReply (PacketWithHeader waiting) { - NS_LOG_FUNCTION (this << waiting); + NS_LOG_FUNCTION (this << waiting.first); NS_ASSERT (m_state == ALIVE || m_state == DEAD); NS_ASSERT (m_pending.empty ()); m_state = WAIT_REPLY; @@ -482,17 +482,18 @@ ArpCache::Entry::IsExpired (void) const } return false; } -Ptr +ArpCache::PacketWithHeader ArpCache::Entry::DequeuePending (void) { NS_LOG_FUNCTION (this); if (m_pending.empty ()) { - return 0; + Ipv4Header h; + return PacketWithHeader (0, h); } else { - Ptr p = m_pending.front (); + PacketWithHeader p = m_pending.front (); m_pending.pop_front (); return p; } diff --git a/src/internet/model/arp-cache.h b/src/internet/model/arp-cache.h index 96904c8674d..8f85da1e6a0 100644 --- a/src/internet/model/arp-cache.h +++ b/src/internet/model/arp-cache.h @@ -39,6 +39,7 @@ namespace ns3 { class NetDevice; class Ipv4Interface; +class Ipv4Header; /** * \ingroup arp @@ -167,6 +168,11 @@ class ArpCache : public Object */ void PrintArpCache (Ptr stream); + /** + * \brief Pair of a packet and an Ipv4 header. + */ + typedef std::pair, Ipv4Header> PacketWithHeader; + /** * \brief A record that that holds information about an ArpCache entry */ @@ -189,7 +195,7 @@ class ArpCache : public Object /** * \param waiting */ - void MarkWaitReply (Ptr waiting); + void MarkWaitReply (PacketWithHeader waiting); /** * \brief Changes the state of this entry to Permanent. * @@ -200,7 +206,7 @@ class ArpCache : public Object * \param waiting * \return */ - bool UpdateWaitReply (Ptr waiting); + bool UpdateWaitReply (PacketWithHeader waiting); /** * \return True if the state of this entry is dead; false otherwise. */ @@ -244,7 +250,7 @@ class ArpCache : public Object * \returns 0 is no packet is pending, the next packet to send if * packets are pending. */ - Ptr DequeuePending (void); + PacketWithHeader DequeuePending (void); /** * \brief Clear the pending packet list */ @@ -290,7 +296,7 @@ class ArpCache : public Object Time m_lastSeen; //!< last moment a packet from that address has been seen Address m_macAddress; //!< entry's MAC address Ipv4Address m_ipv4Address; //!< entry's IP address - std::list > m_pending; //!< list of pending packets for the entry's IP + std::list m_pending; //!< list of pending packets for the entry's IP uint32_t m_retries; //!< rerty counter }; diff --git a/src/internet/model/arp-l3-protocol.cc b/src/internet/model/arp-l3-protocol.cc index 90bb1ce0c3a..fe0dfbf223f 100644 --- a/src/internet/model/arp-l3-protocol.cc +++ b/src/internet/model/arp-l3-protocol.cc @@ -229,10 +229,10 @@ ArpL3Protocol::Receive (Ptr device, Ptr p, uint16_t pro << " for waiting entry -- flush"); Address from_mac = arp.GetSourceHardwareAddress (); entry->MarkAlive (from_mac); - Ptr pending = entry->DequeuePending (); - while (pending != 0) + ArpCache::PacketWithHeader pending = entry->DequeuePending (); + while (pending.first != 0) { - cache->GetInterface ()->Send (pending, + cache->GetInterface ()->Send (pending.first, pending.second, arp.GetSourceIpv4Address ()); pending = entry->DequeuePending (); } @@ -264,7 +264,7 @@ ArpL3Protocol::Receive (Ptr device, Ptr p, uint16_t pro } bool -ArpL3Protocol::Lookup (Ptr packet, Ipv4Address destination, +ArpL3Protocol::Lookup (Ptr packet, const Ipv4Header & ipHeader, Ipv4Address destination, Ptr device, Ptr cache, Address *hardwareDestination) @@ -279,14 +279,14 @@ ArpL3Protocol::Lookup (Ptr packet, Ipv4Address destination, { NS_LOG_LOGIC ("node="<GetId ()<< ", dead entry for " << destination << " expired -- send arp request"); - entry->MarkWaitReply (packet); + entry->MarkWaitReply (ArpCache::PacketWithHeader (packet, ipHeader)); Simulator::Schedule (Time (MilliSeconds (m_requestJitter->GetValue ())), &ArpL3Protocol::SendArpRequest, this, cache, destination); } else if (entry->IsAlive ()) { NS_LOG_LOGIC ("node="<GetId ()<< ", alive entry for " << destination << " expired -- send arp request"); - entry->MarkWaitReply (packet); + entry->MarkWaitReply (ArpCache::PacketWithHeader (packet, ipHeader)); Simulator::Schedule (Time (MilliSeconds (m_requestJitter->GetValue ())), &ArpL3Protocol::SendArpRequest, this, cache, destination); } else @@ -313,7 +313,7 @@ ArpL3Protocol::Lookup (Ptr packet, Ipv4Address destination, { NS_LOG_LOGIC ("node="<GetId ()<< ", wait reply for " << destination << " valid -- drop previous"); - if (!entry->UpdateWaitReply (packet)) + if (!entry->UpdateWaitReply (ArpCache::PacketWithHeader (packet, ipHeader))) { m_dropTrace (packet); } @@ -337,7 +337,7 @@ ArpL3Protocol::Lookup (Ptr packet, Ipv4Address destination, NS_LOG_LOGIC ("node="<GetId ()<< ", no entry for " << destination << " -- send arp request"); entry = cache->Add (destination); - entry->MarkWaitReply (packet); + entry->MarkWaitReply (ArpCache::PacketWithHeader (packet, ipHeader)); Simulator::Schedule (Time (MilliSeconds (m_requestJitter->GetValue ())), &ArpL3Protocol::SendArpRequest, this, cache, destination); } return false; diff --git a/src/internet/model/arp-l3-protocol.h b/src/internet/model/arp-l3-protocol.h index ed6c3189704..d4db3998488 100644 --- a/src/internet/model/arp-l3-protocol.h +++ b/src/internet/model/arp-l3-protocol.h @@ -21,7 +21,7 @@ #define ARP_L3_PROTOCOL_H #include -#include "ns3/ipv4-address.h" +#include "ns3/ipv4-header.h" #include "ns3/net-device.h" #include "ns3/address.h" #include "ns3/ptr.h" @@ -87,13 +87,14 @@ class ArpL3Protocol : public Object /** * \brief Perform an ARP lookup * \param p the packet + * \param ipHeader the IPv4 header * \param destination destination IP address * \param device outgoing device * \param cache ARP cache * \param hardwareDestination filled with the destination MAC address (if the entry exists) * \return true if there is a matching ARP Entry */ - bool Lookup (Ptr p, Ipv4Address destination, + bool Lookup (Ptr p, const Ipv4Header & ipHeader, Ipv4Address destination, Ptr device, Ptr cache, Address *hardwareDestination); diff --git a/src/internet/model/codel-queue.cc b/src/internet/model/codel-queue.cc index 3c897230a75..d2431f2402e 100644 --- a/src/internet/model/codel-queue.cc +++ b/src/internet/model/codel-queue.cc @@ -276,9 +276,10 @@ CoDelQueue::GetMode (void) } bool -CoDelQueue::DoEnqueue (Ptr p) +CoDelQueue::DoEnqueue (Ptr item) { - NS_LOG_FUNCTION (this << p); + NS_LOG_FUNCTION (this << item); + Ptr p = item->GetPacket (); if (m_mode == QUEUE_MODE_PACKETS && (m_packets.size () + 1 > m_maxPackets)) { @@ -301,7 +302,7 @@ CoDelQueue::DoEnqueue (Ptr p) p->AddPacketTag (tag); m_bytesInQueue += p->GetSize (); - m_packets.push (p); + m_packets.push (item); NS_LOG_LOGIC ("Number packets " << m_packets.size ()); NS_LOG_LOGIC ("Number bytes " << m_bytesInQueue); @@ -351,7 +352,7 @@ CoDelQueue::OkToDrop (Ptr p, uint32_t now) return okToDrop; } -Ptr +Ptr CoDelQueue::DoDequeue (void) { NS_LOG_FUNCTION (this); @@ -365,11 +366,12 @@ CoDelQueue::DoDequeue (void) return 0; } uint32_t now = CoDelGetTime (); - Ptr p = m_packets.front (); + Ptr item = m_packets.front (); m_packets.pop (); + Ptr p = item->GetPacket (); m_bytesInQueue -= p->GetSize (); - NS_LOG_LOGIC ("Popped " << p); + NS_LOG_LOGIC ("Popped " << item); NS_LOG_LOGIC ("Number packets remaining " << m_packets.size ()); NS_LOG_LOGIC ("Number bytes remaining " << m_bytesInQueue); @@ -416,11 +418,12 @@ CoDelQueue::DoDequeue (void) ++m_states; return 0; } - p = m_packets.front (); + item = m_packets.front (); m_packets.pop (); + p = item ->GetPacket (); m_bytesInQueue -= p->GetSize (); - NS_LOG_LOGIC ("Popped " << p); + NS_LOG_LOGIC ("Popped " << item); NS_LOG_LOGIC ("Number packets remaining " << m_packets.size ()); NS_LOG_LOGIC ("Number bytes remaining " << m_bytesInQueue); @@ -466,11 +469,12 @@ CoDelQueue::DoDequeue (void) } else { - p = m_packets.front (); + item = m_packets.front (); m_packets.pop (); + p = item->GetPacket (); m_bytesInQueue -= p->GetSize (); - NS_LOG_LOGIC ("Popped " << p); + NS_LOG_LOGIC ("Popped " << item); NS_LOG_LOGIC ("Number packets remaining " << m_packets.size ()); NS_LOG_LOGIC ("Number bytes remaining " << m_bytesInQueue); @@ -501,7 +505,7 @@ CoDelQueue::DoDequeue (void) } } ++m_states; - return p; + return item; } uint32_t @@ -552,7 +556,7 @@ CoDelQueue::GetDropNext (void) return m_dropNext; } -Ptr +Ptr CoDelQueue::DoPeek (void) const { NS_LOG_FUNCTION (this); @@ -563,12 +567,12 @@ CoDelQueue::DoPeek (void) const return 0; } - Ptr p = m_packets.front (); + Ptr item = m_packets.front (); NS_LOG_LOGIC ("Number packets " << m_packets.size ()); NS_LOG_LOGIC ("Number bytes " << m_bytesInQueue); - return p; + return item; } bool diff --git a/src/internet/model/codel-queue.h b/src/internet/model/codel-queue.h index 3dfe666a652..0519c25ff72 100644 --- a/src/internet/model/codel-queue.h +++ b/src/internet/model/codel-queue.h @@ -142,10 +142,10 @@ class CoDelQueue : public Queue /** * \brief Add a packet to the queue * - * \param p The packet to be added + * \param item The item to be added * \returns True if the packet can be added, False if the packet is dropped due to full queue */ - virtual bool DoEnqueue (Ptr p); + virtual bool DoEnqueue (Ptr item); /** * \brief Remove a packet from queue based on the current state @@ -156,9 +156,9 @@ class CoDelQueue : public Queue * * \returns The packet that is examined */ - virtual Ptr DoDequeue (void); + virtual Ptr DoDequeue (void); - virtual Ptr DoPeek (void) const; + virtual Ptr DoPeek (void) const; /** * \brief Calculate the reciprocal square root of m_count by using Newton's method @@ -223,7 +223,7 @@ class CoDelQueue : public Queue */ uint32_t Time2CoDel (Time t); - std::queue > m_packets; //!< The packet queue + std::queue > m_packets; //!< The packet queue uint32_t m_maxPackets; //!< Max # of packets accepted by the queue uint32_t m_maxBytes; //!< Max # of bytes accepted by the queue TracedValue m_bytesInQueue; //!< The total number of bytes in queue diff --git a/src/internet/model/icmpv6-l4-protocol.cc b/src/internet/model/icmpv6-l4-protocol.cc index 66e894de743..b028ad03daf 100644 --- a/src/internet/model/icmpv6-l4-protocol.cc +++ b/src/internet/model/icmpv6-l4-protocol.cc @@ -35,7 +35,6 @@ #include "ipv6-l3-protocol.h" #include "ipv6-interface.h" #include "icmpv6-l4-protocol.h" -#include "ndisc-cache.h" namespace ns3 { @@ -185,11 +184,11 @@ void Icmpv6L4Protocol::DoDAD (Ipv6Address target, Ptr interface) /** \todo disable multicast loopback to prevent NS probing to be received by the sender */ - Ptr p = ForgeNS ("::",Ipv6Address::MakeSolicitedAddress (target), target, interface->GetDevice ()->GetAddress ()); + NdiscCache::PacketWithHeader p = ForgeNS ("::",Ipv6Address::MakeSolicitedAddress (target), target, interface->GetDevice ()->GetAddress ()); /* update last packet UID */ - interface->SetNsDadUid (target, p->GetUid ()); - Simulator::Schedule (Time (MilliSeconds (m_solicitationJitter->GetValue ())), &Ipv6Interface::Send, interface, p, Ipv6Address::MakeSolicitedAddress (target)); + interface->SetNsDadUid (target, p.first->GetUid ()); + Simulator::Schedule (Time (MilliSeconds (m_solicitationJitter->GetValue ())), &Ipv6Interface::Send, interface, p.first, p.second, Ipv6Address::MakeSolicitedAddress (target)); } enum IpL4Protocol::RxStatus Icmpv6L4Protocol::Receive (Ptr packet, Ipv4Header const &header, Ptr interface) @@ -377,7 +376,7 @@ void Icmpv6L4Protocol::ReceiveLLA (Icmpv6OptionLinkLayerAddress lla, Ipv6Address } else { - std::list > waiting; + std::list waiting; if (entry->IsIncomplete ()) { entry->StopNudTimer (); @@ -385,9 +384,9 @@ void Icmpv6L4Protocol::ReceiveLLA (Icmpv6OptionLinkLayerAddress lla, Ipv6Address waiting = entry->MarkReachable (lla.GetAddress ()); entry->StartReachableTimer (); // send out waiting packet - for (std::list >::const_iterator it = waiting.begin (); it != waiting.end (); it++) + for (std::list::const_iterator it = waiting.begin (); it != waiting.end (); it++) { - cache->GetInterface ()->Send (*it, src); + cache->GetInterface ()->Send (it->first, it->second, src); } entry->ClearWaitingPacket (); } @@ -407,9 +406,9 @@ void Icmpv6L4Protocol::ReceiveLLA (Icmpv6OptionLinkLayerAddress lla, Ipv6Address waiting = entry->MarkReachable (lla.GetAddress ()); if (entry->IsProbe ()) { - for (std::list >::const_iterator it = waiting.begin (); it != waiting.end (); it++) + for (std::list::const_iterator it = waiting.begin (); it != waiting.end (); it++) { - cache->GetInterface ()->Send (*it, src); + cache->GetInterface ()->Send (it->first, it->second, src); } } entry->StartReachableTimer (); @@ -545,13 +544,13 @@ void Icmpv6L4Protocol::HandleNS (Ptr packet, Ipv6Address const &src, Ipv } hardwareAddress = interface->GetDevice ()->GetAddress (); - Ptr p = ForgeNA (target.IsLinkLocal () ? interface->GetLinkLocalAddress ().GetAddress () : ifaddr.GetAddress (), src.IsAny () ? Ipv6Address::GetAllNodesMulticast () : src, &hardwareAddress, flags ); - interface->Send (p, src.IsAny () ? Ipv6Address::GetAllNodesMulticast () : src); + NdiscCache::PacketWithHeader p = ForgeNA (target.IsLinkLocal () ? interface->GetLinkLocalAddress ().GetAddress () : ifaddr.GetAddress (), src.IsAny () ? Ipv6Address::GetAllNodesMulticast () : src, &hardwareAddress, flags ); + interface->Send (p.first, p.second, src.IsAny () ? Ipv6Address::GetAllNodesMulticast () : src); /* not a NS for us discard it */ } -Ptr Icmpv6L4Protocol::ForgeRS (Ipv6Address src, Ipv6Address dst, Address hardwareAddress) +NdiscCache::PacketWithHeader Icmpv6L4Protocol::ForgeRS (Ipv6Address src, Ipv6Address dst, Address hardwareAddress) { NS_LOG_FUNCTION (this << src << dst << hardwareAddress); Ptr p = Create (); @@ -571,12 +570,10 @@ Ptr Icmpv6L4Protocol::ForgeRS (Ipv6Address src, Ipv6Address dst, Address ipHeader.SetPayloadLength (p->GetSize ()); ipHeader.SetHopLimit (255); - p->AddHeader (ipHeader); - - return p; + return NdiscCache::PacketWithHeader (p, ipHeader); } -Ptr Icmpv6L4Protocol::ForgeEchoRequest (Ipv6Address src, Ipv6Address dst, uint16_t id, uint16_t seq, Ptr data) +NdiscCache::PacketWithHeader Icmpv6L4Protocol::ForgeEchoRequest (Ipv6Address src, Ipv6Address dst, uint16_t id, uint16_t seq, Ptr data) { NS_LOG_FUNCTION (this << src << dst << id << seq << data); Ptr p = data->Copy (); @@ -595,9 +592,7 @@ Ptr Icmpv6L4Protocol::ForgeEchoRequest (Ipv6Address src, Ipv6Address dst ipHeader.SetPayloadLength (p->GetSize ()); ipHeader.SetHopLimit (255); - p->AddHeader (ipHeader); - - return p; + return NdiscCache::PacketWithHeader (p, ipHeader); } void Icmpv6L4Protocol::HandleNA (Ptr packet, Ipv6Address const &src, Ipv6Address const &dst, Ptr interface) @@ -612,7 +607,7 @@ void Icmpv6L4Protocol::HandleNA (Ptr packet, Ipv6Address const &src, Ipv Address hardwareAddress; NdiscCache::Entry* entry = 0; Ptr cache = FindCache (interface->GetDevice ()); - std::list > waiting; + std::list waiting; /* check if we have something in our cache */ entry = cache->Lookup (target); @@ -670,9 +665,9 @@ void Icmpv6L4Protocol::HandleNA (Ptr packet, Ipv6Address const &src, Ipv waiting = entry->MarkReachable (lla.GetAddress ()); entry->StartReachableTimer (); /* send out waiting packet */ - for (std::list >::const_iterator it = waiting.begin (); it != waiting.end (); it++) + for (std::list::const_iterator it = waiting.begin (); it != waiting.end (); it++) { - cache->GetInterface ()->Send (*it, src); + cache->GetInterface ()->Send (it->first, it->second, src); } entry->ClearWaitingPacket (); } @@ -713,9 +708,9 @@ void Icmpv6L4Protocol::HandleNA (Ptr packet, Ipv6Address const &src, Ipv if (entry->IsProbe ()) { waiting = entry->MarkReachable (lla.GetAddress ()); - for (std::list >::const_iterator it = waiting.begin (); it != waiting.end (); it++) + for (std::list::const_iterator it = waiting.begin (); it != waiting.end (); it++) { - cache->GetInterface ()->Send (*it, src); + cache->GetInterface ()->Send (it->first, it->second, src); } entry->ClearWaitingPacket (); } @@ -1179,7 +1174,7 @@ void Icmpv6L4Protocol::SendRedirection (Ptr redirectedPacket, Ipv6Addres SendMessage (p, src, dst, 64); } -Ptr Icmpv6L4Protocol::ForgeNA (Ipv6Address src, Ipv6Address dst, Address* hardwareAddress, uint8_t flags) +NdiscCache::PacketWithHeader Icmpv6L4Protocol::ForgeNA (Ipv6Address src, Ipv6Address dst, Address* hardwareAddress, uint8_t flags) { NS_LOG_FUNCTION (this << src << dst << hardwareAddress << (uint32_t)flags); Ptr p = Create (); @@ -1216,12 +1211,10 @@ Ptr Icmpv6L4Protocol::ForgeNA (Ipv6Address src, Ipv6Address dst, Address ipHeader.SetPayloadLength (p->GetSize ()); ipHeader.SetHopLimit (255); - p->AddHeader (ipHeader); - - return p; + return NdiscCache::PacketWithHeader (p, ipHeader); } -Ptr Icmpv6L4Protocol::ForgeNS (Ipv6Address src, Ipv6Address dst, Ipv6Address target, Address hardwareAddress) +NdiscCache::PacketWithHeader Icmpv6L4Protocol::ForgeNS (Ipv6Address src, Ipv6Address dst, Ipv6Address target, Address hardwareAddress) { NS_LOG_FUNCTION (this << src << dst << target << hardwareAddress); Ptr p = Create (); @@ -1247,9 +1240,7 @@ Ptr Icmpv6L4Protocol::ForgeNS (Ipv6Address src, Ipv6Address dst, Ipv6Add ipHeader.SetPayloadLength (p->GetSize ()); ipHeader.SetHopLimit (255); - p->AddHeader (ipHeader); - - return p; + return NdiscCache::PacketWithHeader (p, ipHeader); } Ptr Icmpv6L4Protocol::FindCache (Ptr device) @@ -1312,9 +1303,9 @@ bool Icmpv6L4Protocol::Lookup (Ipv6Address dst, Ptr device, Ptr p, Ipv6Address dst, Ptr device, Ptr cache, Address* hardwareDestination) +bool Icmpv6L4Protocol::Lookup (Ptr p, const Ipv6Header & ipHeader, Ipv6Address dst, Ptr device, Ptr cache, Address* hardwareDestination) { - NS_LOG_FUNCTION (this << p << dst << device << cache << hardwareDestination); + NS_LOG_FUNCTION (this << p << ipHeader << dst << device << cache << hardwareDestination); if (!cache) { @@ -1347,7 +1338,7 @@ bool Icmpv6L4Protocol::Lookup (Ptr p, Ipv6Address dst, Ptr de else /* INCOMPLETE or PROBE */ { /* queue packet */ - entry->AddWaitingPacket (p); + entry->AddWaitingPacket (NdiscCache::PacketWithHeader (p, ipHeader)); return false; } } @@ -1358,7 +1349,7 @@ bool Icmpv6L4Protocol::Lookup (Ptr p, Ipv6Address dst, Ptr de */ Ipv6Address addr; NdiscCache::Entry* entry = cache->Add (dst); - entry->MarkIncomplete (p); + entry->MarkIncomplete (NdiscCache::PacketWithHeader (p, ipHeader)); entry->SetRouter (false); if (dst.IsLinkLocal ()) diff --git a/src/internet/model/icmpv6-l4-protocol.h b/src/internet/model/icmpv6-l4-protocol.h index 5f5e03b4702..71511f18154 100644 --- a/src/internet/model/icmpv6-l4-protocol.h +++ b/src/internet/model/icmpv6-l4-protocol.h @@ -30,6 +30,7 @@ #include "icmpv6-header.h" #include "ip-l4-protocol.h" +#include "ndisc-cache.h" namespace ns3 { @@ -37,7 +38,6 @@ class NetDevice; class Node; class Packet; class TraceContext; -class NdiscCache; /** * \class Icmpv6L4Protocol @@ -301,7 +301,7 @@ class Icmpv6L4Protocol : public IpL4Protocol * \param hardwareAddress our mac address * \return NS packet (with IPv6 header) */ - Ptr ForgeNS (Ipv6Address src, Ipv6Address dst, Ipv6Address target, Address hardwareAddress); + NdiscCache::PacketWithHeader ForgeNS (Ipv6Address src, Ipv6Address dst, Ipv6Address target, Address hardwareAddress); /** * \brief Forge a Neighbor Advertisement. @@ -311,7 +311,7 @@ class Icmpv6L4Protocol : public IpL4Protocol * \param flags flags (bitfield => R (4), S (2), O (1)) * \return NA packet (with IPv6 header) */ - Ptr ForgeNA (Ipv6Address src, Ipv6Address dst, Address* hardwareAddress, uint8_t flags); + NdiscCache::PacketWithHeader ForgeNA (Ipv6Address src, Ipv6Address dst, Address* hardwareAddress, uint8_t flags); /** * \brief Forge a Router Solicitation. @@ -320,7 +320,7 @@ class Icmpv6L4Protocol : public IpL4Protocol * \param hardwareAddress our mac address * \return RS packet (with IPv6 header) */ - Ptr ForgeRS (Ipv6Address src, Ipv6Address dst, Address hardwareAddress); + NdiscCache::PacketWithHeader ForgeRS (Ipv6Address src, Ipv6Address dst, Address hardwareAddress); /** * \brief Forge an Echo Request. @@ -331,7 +331,7 @@ class Icmpv6L4Protocol : public IpL4Protocol * \param data the data * \return Echo Request packet (with IPv6 header) */ - Ptr ForgeEchoRequest (Ipv6Address src, Ipv6Address dst, uint16_t id, uint16_t seq, Ptr data); + NdiscCache::PacketWithHeader ForgeEchoRequest (Ipv6Address src, Ipv6Address dst, uint16_t id, uint16_t seq, Ptr data); /** * \brief Receive method. @@ -381,13 +381,14 @@ class Icmpv6L4Protocol : public IpL4Protocol * * It also send NS request to target and store the waiting packet. * \param p the packet + * \param ipHeader IPv6 header * \param dst destination address * \param device device * \param cache the neighbor cache * \param hardwareDestination hardware address * \return true if the address is in the ND cache, the hardwareDestination is updated. */ - bool Lookup (Ptr p, Ipv6Address dst, Ptr device, Ptr cache, Address* hardwareDestination); + bool Lookup (Ptr p, const Ipv6Header & ipHeader, Ipv6Address dst, Ptr device, Ptr cache, Address* hardwareDestination); /** * \brief Send a Router Solicitation. diff --git a/src/internet/model/ipv4-header.cc b/src/internet/model/ipv4-header.cc index 4dd5f415145..ddf013ed265 100644 --- a/src/internet/model/ipv4-header.cc +++ b/src/internet/model/ipv4-header.cc @@ -41,7 +41,8 @@ Ipv4Header::Ipv4Header () m_fragmentOffset (0), m_checksum (0), m_goodChecksum (true), - m_headerSize(5*4) + m_headerSize(5*4), + m_version (4) { } @@ -110,9 +111,9 @@ Ipv4Header::GetDscp (void) const } std::string -Ipv4Header::DscpTypeToString (DscpType dscp) const +Ipv4Header::DscpTypeToString (DscpType dscp) { - NS_LOG_FUNCTION (this << dscp); + NS_LOG_FUNCTION_NOARGS (); switch (dscp) { case DscpDefault: @@ -196,6 +197,12 @@ Ipv4Header::GetTos (void) const NS_LOG_FUNCTION (this); return m_tos; } +uint8_t +Ipv4Header::GetVersion (void) const +{ + NS_LOG_FUNCTION (this); + return m_version; +} void Ipv4Header::SetMoreFragments (void) { @@ -425,9 +432,9 @@ Ipv4Header::Deserialize (Buffer::Iterator start) NS_LOG_FUNCTION (this << &start); Buffer::Iterator i = start; uint8_t verIhl = i.ReadU8 (); + m_version = verIhl >> 4; uint8_t ihl = verIhl & 0x0f; uint16_t headerSize = ihl * 4; - NS_ASSERT ((verIhl >> 4) == 4); m_tos = i.ReadU8 (); uint16_t size = i.ReadNtohU16 (); m_payloadSize = size - headerSize; diff --git a/src/internet/model/ipv4-header.h b/src/internet/model/ipv4-header.h index a338d30f8b1..d667c621e89 100644 --- a/src/internet/model/ipv4-header.h +++ b/src/internet/model/ipv4-header.h @@ -167,6 +167,10 @@ class Ipv4Header : public Header * \returns the TOS field of this packet. */ uint8_t GetTos (void) const; + /** + * \returns the version field of this packet (typically '4'). + */ + uint8_t GetVersion (void) const; /** * \returns the DSCP field of this packet. */ @@ -175,7 +179,7 @@ class Ipv4Header : public Header * \param dscp the dscp * \returns std::string of DSCPType */ - std::string DscpTypeToString (DscpType dscp) const; + static std::string DscpTypeToString (DscpType dscp); /** * \returns the ECN field of this packet. */ @@ -254,6 +258,7 @@ class Ipv4Header : public Header uint16_t m_checksum; //!< checksum bool m_goodChecksum; //!< true if checksum is correct uint16_t m_headerSize; //!< IP header size + uint16_t m_version; //!< IP version (4) }; } // namespace ns3 diff --git a/src/internet/model/ipv4-interface.cc b/src/internet/model/ipv4-interface.cc index bd5978c2141..18a6cbe644f 100644 --- a/src/internet/model/ipv4-interface.cc +++ b/src/internet/model/ipv4-interface.cc @@ -20,7 +20,6 @@ #include "ipv4-interface.h" #include "loopback-net-device.h" -#include "ns3/ipv4-address.h" #include "ipv4-l3-protocol.h" #include "arp-l3-protocol.h" #include "arp-cache.h" @@ -29,6 +28,7 @@ #include "ns3/packet.h" #include "ns3/node.h" #include "ns3/pointer.h" +#include "ns3/traffic-control-layer.h" namespace ns3 { @@ -198,20 +198,25 @@ Ipv4Interface::SetForwarding (bool val) } void -Ipv4Interface::Send (Ptr p, Ipv4Address dest) +Ipv4Interface::Send (Ptr p, const Ipv4Header & hdr, Ipv4Address dest) { NS_LOG_FUNCTION (this << *p << dest); if (!IsUp ()) { return; } - // Check for a loopback device + + Ptr tc = m_node->GetObject (); + NS_ASSERT (tc != 0); + + // Check for a loopback device, if it's the case we don't pass through + // traffic control layer if (DynamicCast (m_device)) { /// \todo additional checks needed here (such as whether multicast /// goes to loopback)? - m_device->Send (p, m_device->GetBroadcast (), - Ipv4L3Protocol::PROT_NUMBER); + p->AddHeader (hdr); + m_device->Send (p, m_device->GetBroadcast (), Ipv4L3Protocol::PROT_NUMBER); return; } // is this packet aimed at a local interface ? @@ -219,13 +224,11 @@ Ipv4Interface::Send (Ptr p, Ipv4Address dest) { if (dest == (*i).GetLocal ()) { - Ptr ipv4 = m_node->GetObject (); - - ipv4->Receive (m_device, p, Ipv4L3Protocol::PROT_NUMBER, - m_device->GetBroadcast (), - m_device->GetBroadcast (), - NetDevice::PACKET_HOST // note: linux uses PACKET_LOOPBACK here - ); + p->AddHeader (hdr); + tc->Receive (m_device, p, Ipv4L3Protocol::PROT_NUMBER, + m_device->GetBroadcast (), + m_device->GetBroadcast (), + NetDevice::PACKET_HOST); return; } } @@ -266,22 +269,20 @@ Ipv4Interface::Send (Ptr p, Ipv4Address dest) if (!found) { NS_LOG_LOGIC ("ARP Lookup"); - found = arp->Lookup (p, dest, m_device, m_cache, &hardwareDestination); + found = arp->Lookup (p, hdr, dest, m_device, m_cache, &hardwareDestination); } } if (found) { NS_LOG_LOGIC ("Address Resolved. Send."); - m_device->Send (p, hardwareDestination, - Ipv4L3Protocol::PROT_NUMBER); + tc->Send (m_device, p, hdr, hardwareDestination, Ipv4L3Protocol::PROT_NUMBER); } } else { NS_LOG_LOGIC ("Doesn't need ARP"); - m_device->Send (p, m_device->GetBroadcast (), - Ipv4L3Protocol::PROT_NUMBER); + tc->Send (m_device, p, hdr, m_device->GetBroadcast (), Ipv4L3Protocol::PROT_NUMBER); } } diff --git a/src/internet/model/ipv4-interface.h b/src/internet/model/ipv4-interface.h index 4bf984e7e7a..bb423ed39ef 100644 --- a/src/internet/model/ipv4-interface.h +++ b/src/internet/model/ipv4-interface.h @@ -23,7 +23,7 @@ #define IPV4_INTERFACE_H #include -#include "ns3/ipv4-address.h" +#include "ns3/ipv4-header.h" #include "ns3/ipv4-interface-address.h" #include "ns3/ptr.h" #include "ns3/object.h" @@ -139,12 +139,13 @@ class Ipv4Interface : public Object /** * \param p packet to send + * \param hdr IPv4 header * \param dest next hop address of packet. * * This method will eventually call the private * SendTo method which must be implemented by subclasses. */ - void Send (Ptr p, Ipv4Address dest); + void Send (Ptr p, const Ipv4Header & hdr, Ipv4Address dest); /** * \param address The Ipv4InterfaceAddress to add to the interface diff --git a/src/internet/model/ipv4-l3-protocol.cc b/src/internet/model/ipv4-l3-protocol.cc index 591bc1d6c78..4472be0d814 100644 --- a/src/internet/model/ipv4-l3-protocol.cc +++ b/src/internet/model/ipv4-l3-protocol.cc @@ -32,6 +32,7 @@ #include "ns3/ipv4-header.h" #include "ns3/boolean.h" #include "ns3/ipv4-routing-table-entry.h" +#include "ns3/traffic-control-layer.h" #include "loopback-net-device.h" #include "arp-l3-protocol.h" @@ -369,12 +370,21 @@ uint32_t Ipv4L3Protocol::AddInterface (Ptr device) { NS_LOG_FUNCTION (this << device); + NS_ASSERT (m_node != 0); - Ptr node = GetObject (); - node->RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, this), - Ipv4L3Protocol::PROT_NUMBER, device); - node->RegisterProtocolHandler (MakeCallback (&ArpL3Protocol::Receive, PeekPointer (GetObject ())), - ArpL3Protocol::PROT_NUMBER, device); + 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); Ptr interface = CreateObject (); interface->SetNode (m_node); @@ -559,7 +569,6 @@ Ipv4L3Protocol::Receive ( Ptr device, Ptr p, uint16_t p { if (ipv4Interface->IsUp ()) { - m_rxTrace (packet, m_node->GetObject (), interface); break; } else @@ -579,6 +588,7 @@ Ipv4L3Protocol::Receive ( Ptr device, Ptr p, uint16_t p ipHeader.EnableChecksum (); } packet->RemoveHeader (ipHeader); + m_rxTrace (ipHeader, packet, m_node->GetObject (), interface); // Trim any residual frame padding from underlying devices if (ipHeader.GetPayloadSize () < packet->GetSize ()) @@ -726,9 +736,8 @@ Ipv4L3Protocol::Send (Ptr packet, NS_ASSERT (packetCopy->GetSize () <= outInterface->GetDevice ()->GetMtu ()); m_sendOutgoingTrace (ipHeader, packetCopy, ifaceIndex); - packetCopy->AddHeader (ipHeader); - m_txTrace (packetCopy, m_node->GetObject (), ifaceIndex); - outInterface->Send (packetCopy, destination); + m_txTrace (ipHeader, packetCopy, m_node->GetObject (), ifaceIndex); + outInterface->Send (packetCopy, ipHeader, destination); } return; } @@ -750,9 +759,8 @@ Ipv4L3Protocol::Send (Ptr packet, ipHeader = BuildHeader (source, destination, protocol, packet->GetSize (), ttl, tos, mayFragment); Ptr packetCopy = packet->Copy (); m_sendOutgoingTrace (ipHeader, packetCopy, ifaceIndex); - packetCopy->AddHeader (ipHeader); - m_txTrace (packetCopy, m_node->GetObject (), ifaceIndex); - outInterface->Send (packetCopy, destination); + m_txTrace (ipHeader, packetCopy, m_node->GetObject (), ifaceIndex); + outInterface->Send (packetCopy, ipHeader, destination); return; } } @@ -867,7 +875,6 @@ Ipv4L3Protocol::SendRealOut (Ptr route, m_dropTrace (ipHeader, packet, DROP_NO_ROUTE, m_node->GetObject (), 0); return; } - packet->AddHeader (ipHeader); Ptr outDev = route->GetOutputDevice (); int32_t interface = GetInterfaceForDevice (outDev); NS_ASSERT (interface >= 0); @@ -879,27 +886,25 @@ Ipv4L3Protocol::SendRealOut (Ptr route, if (outInterface->IsUp ()) { NS_LOG_LOGIC ("Send to gateway " << route->GetGateway ()); - if ( packet->GetSize () > outInterface->GetDevice ()->GetMtu () ) + if ( packet->GetSize () + ipHeader.GetSerializedSize () > outInterface->GetDevice ()->GetMtu () ) { - std::list > listFragments; - DoFragmentation (packet, outInterface->GetDevice ()->GetMtu (), listFragments); - for ( std::list >::iterator it = listFragments.begin (); it != listFragments.end (); it++ ) + std::list listFragments; + DoFragmentation (packet, ipHeader, outInterface->GetDevice ()->GetMtu (), listFragments); + for ( std::list::iterator it = listFragments.begin (); it != listFragments.end (); it++ ) { - m_txTrace (*it, m_node->GetObject (), interface); - outInterface->Send (*it, route->GetGateway ()); + m_txTrace (it->second, it->first, m_node->GetObject (), interface); + outInterface->Send (it->first, it->second, route->GetGateway ()); } } else { - m_txTrace (packet, m_node->GetObject (), interface); - outInterface->Send (packet, route->GetGateway ()); + m_txTrace (ipHeader, packet, m_node->GetObject (), interface); + outInterface->Send (packet, ipHeader, route->GetGateway ()); } } else { NS_LOG_LOGIC ("Dropping -- outgoing interface is down: " << route->GetGateway ()); - Ipv4Header ipHeader; - packet->RemoveHeader (ipHeader); m_dropTrace (ipHeader, packet, DROP_INTERFACE_DOWN, m_node->GetObject (), interface); } } @@ -908,28 +913,26 @@ Ipv4L3Protocol::SendRealOut (Ptr route, if (outInterface->IsUp ()) { NS_LOG_LOGIC ("Send to destination " << ipHeader.GetDestination ()); - if ( packet->GetSize () > outInterface->GetDevice ()->GetMtu () ) + if ( packet->GetSize () + ipHeader.GetSerializedSize () > outInterface->GetDevice ()->GetMtu () ) { - std::list > listFragments; - DoFragmentation (packet, outInterface->GetDevice ()->GetMtu (), listFragments); - for ( std::list >::iterator it = listFragments.begin (); it != listFragments.end (); it++ ) + std::list listFragments; + DoFragmentation (packet, ipHeader, outInterface->GetDevice ()->GetMtu (), listFragments); + for ( std::list::iterator it = listFragments.begin (); it != listFragments.end (); it++ ) { - NS_LOG_LOGIC ("Sending fragment " << **it ); - m_txTrace (*it, m_node->GetObject (), interface); - outInterface->Send (*it, ipHeader.GetDestination ()); + NS_LOG_LOGIC ("Sending fragment " << *(it->first) ); + m_txTrace (it->second, it->first, m_node->GetObject (), interface); + outInterface->Send (it->first, it->second, ipHeader.GetDestination ()); } } else { - m_txTrace (packet, m_node->GetObject (), interface); - outInterface->Send (packet, ipHeader.GetDestination ()); + m_txTrace (ipHeader, packet, m_node->GetObject (), interface); + outInterface->Send (packet, ipHeader, ipHeader.GetDestination ()); } } else { NS_LOG_LOGIC ("Dropping -- outgoing interface is down: " << ipHeader.GetDestination ()); - Ipv4Header ipHeader; - packet->RemoveHeader (ipHeader); m_dropTrace (ipHeader, packet, DROP_INTERFACE_DOWN, m_node->GetObject (), interface); } } @@ -1319,7 +1322,7 @@ Ipv4L3Protocol::RouteInputError (Ptr p, const Ipv4Header & ipHeade } void -Ipv4L3Protocol::DoFragmentation (Ptr packet, uint32_t outIfaceMtu, std::list >& listFragments) +Ipv4L3Protocol::DoFragmentation (Ptr packet, const Ipv4Header & ipv4Header, uint32_t outIfaceMtu, std::list& listFragments) { // BEWARE: here we do assume that the header options are not present. // a much more complex handling is necessary in case there are options. @@ -1330,9 +1333,6 @@ Ipv4L3Protocol::DoFragmentation (Ptr packet, uint32_t outIfaceMtu, std:: Ptr p = packet->Copy (); - Ipv4Header ipv4Header; - p->RemoveHeader (ipv4Header); - NS_ASSERT_MSG( (ipv4Header.GetSerializedSize() == 5*4), "IPv4 fragmentation implementation only works without option headers." ); @@ -1394,14 +1394,14 @@ Ipv4L3Protocol::DoFragmentation (Ptr packet, uint32_t outIfaceMtu, std:: NS_LOG_LOGIC ("Fragment check - " << fragmentHeader.GetFragmentOffset () ); NS_LOG_LOGIC ("New fragment Header " << fragmentHeader); - fragment->AddHeader (fragmentHeader); std::ostringstream oss; + oss << fragmentHeader; fragment->Print (oss); NS_LOG_LOGIC ("New fragment " << *fragment); - listFragments.push_back (fragment); + listFragments.push_back (PacketWithHeader (fragment, fragmentHeader)); offset += currentFragmentablePartSize; diff --git a/src/internet/model/ipv4-l3-protocol.h b/src/internet/model/ipv4-l3-protocol.h index 4ace7edbed6..771c9b709d1 100644 --- a/src/internet/model/ipv4-l3-protocol.h +++ b/src/internet/model/ipv4-l3-protocol.h @@ -52,7 +52,6 @@ class Ipv4RawSocketImpl; class IpL4Protocol; class Icmpv4L4Protocol; - /** * \brief Implement the Ipv4 layer. * @@ -282,6 +281,7 @@ class Ipv4L3Protocol : public Ipv4 /** * TracedCallback signature for packet transmission or reception events. * + * \param [in] header The Ipv4Header. * \param [in] packet The packet. * \param [in] ipv4 * \param [in] interface @@ -289,7 +289,7 @@ class Ipv4L3Protocol : public Ipv4 * and will be changed to \c Ptr in a future release. */ typedef void (* TxRxTracedCallback) - (Ptr packet, Ptr ipv4, uint32_t interface); + (const Ipv4Header & header, Ptr packet, Ptr ipv4, uint32_t interface); /** * TracedCallback signature for packet drop events. @@ -434,13 +434,19 @@ class Ipv4L3Protocol : public Ipv4 */ bool IsUnicast (Ipv4Address ad, Ipv4Mask interfaceMask) const; + /** + * \brief Pair of a packet and an Ipv4 header. + */ + typedef std::pair, Ipv4Header> PacketWithHeader; + /** * \brief Fragment a packet * \param packet the packet + * \param ipHeader the IPv4 header * \param outIfaceMtu the MTU of the interface * \param listFragments the list of fragments */ - void DoFragmentation (Ptr packet, uint32_t outIfaceMtu, std::list >& listFragments); + void DoFragmentation (Ptr packet, const Ipv4Header & ipv4Header, uint32_t outIfaceMtu, std::list& listFragments); /** * \brief Process a packet fragment @@ -494,15 +500,14 @@ class Ipv4L3Protocol : public Ipv4 /// Trace of locally delivered packets TracedCallback, uint32_t> m_localDeliverTrace; - // The following two traces pass a packet with an IP header /// Trace of transmitted packets /// \deprecated The non-const \c Ptr argument is deprecated /// and will be changed to \c Ptr in a future release. - TracedCallback, Ptr, uint32_t> m_txTrace; + TracedCallback, Ptr, uint32_t> m_txTrace; /// Trace of received packets /// \deprecated The non-const \c Ptr argument is deprecated /// and will be changed to \c Ptr in a future release. - TracedCallback, Ptr, uint32_t> m_rxTrace; + TracedCallback, Ptr, uint32_t> m_rxTrace; // (ifindex not valid if reason is DROP_NO_ROUTE) /// Trace of dropped packets /// \deprecated The non-const \c Ptr argument is deprecated diff --git a/src/internet/model/ipv4-packet-probe.cc b/src/internet/model/ipv4-packet-probe.cc index 713fb57845d..a9bd7e1c8e0 100644 --- a/src/internet/model/ipv4-packet-probe.cc +++ b/src/internet/model/ipv4-packet-probe.cc @@ -69,26 +69,27 @@ Ipv4PacketProbe::~Ipv4PacketProbe () } void -Ipv4PacketProbe::SetValue (Ptr packet, Ptr ipv4, uint32_t interface) +Ipv4PacketProbe::SetValue (const Ipv4Header & header, Ptr packet, Ptr ipv4, uint32_t interface) { - NS_LOG_FUNCTION (this << packet << ipv4 << interface); + NS_LOG_FUNCTION (this << header << packet << ipv4 << interface); + m_header = header; m_packet = packet; m_ipv4 = ipv4; m_interface = interface; - m_output (packet, ipv4, interface); + m_output (header, packet, ipv4, interface); - uint32_t packetSizeNew = packet->GetSize (); + uint32_t packetSizeNew = packet->GetSize () + header.GetSerializedSize (); m_outputBytes (m_packetSizeOld, packetSizeNew); m_packetSizeOld = packetSizeNew; } void -Ipv4PacketProbe::SetValueByPath (std::string path, Ptr packet, Ptr ipv4, uint32_t interface) +Ipv4PacketProbe::SetValueByPath (std::string path, const Ipv4Header & header, Ptr packet, Ptr ipv4, uint32_t interface) { - NS_LOG_FUNCTION (path << packet << ipv4 << interface); + NS_LOG_FUNCTION (path << header << packet << ipv4 << interface); Ptr probe = Names::Find (path); NS_ASSERT_MSG (probe, "Error: Can't find probe for path " << path); - probe->SetValue (packet, ipv4, interface); + probe->SetValue (header, packet, ipv4, interface); } bool @@ -109,17 +110,18 @@ Ipv4PacketProbe::ConnectByPath (std::string path) } void -Ipv4PacketProbe::TraceSink (Ptr packet, Ptr ipv4, uint32_t interface) +Ipv4PacketProbe::TraceSink (const Ipv4Header & header, Ptr packet, Ptr ipv4, uint32_t interface) { - NS_LOG_FUNCTION (this << packet << ipv4 << interface); + NS_LOG_FUNCTION (this << header << packet << ipv4 << interface); if (IsEnabled ()) { + m_header = header; m_packet = packet; m_ipv4 = ipv4; m_interface = interface; - m_output (packet, ipv4, interface); + m_output (header, packet, ipv4, interface); - uint32_t packetSizeNew = packet->GetSize (); + uint32_t packetSizeNew = packet->GetSize () + header.GetSerializedSize (); m_outputBytes (m_packetSizeOld, packetSizeNew); m_packetSizeOld = packetSizeNew; } diff --git a/src/internet/model/ipv4-packet-probe.h b/src/internet/model/ipv4-packet-probe.h index a064d4ca49e..f521b141155 100644 --- a/src/internet/model/ipv4-packet-probe.h +++ b/src/internet/model/ipv4-packet-probe.h @@ -30,6 +30,7 @@ #include "ns3/nstime.h" #include "ns3/packet.h" #include "ns3/ipv4.h" +#include "ns3/ipv4-header.h" #include "ns3/traced-value.h" #include "ns3/simulator.h" #include "ns3/probe.h" @@ -37,11 +38,11 @@ namespace ns3 { /** - * This class is designed to probe an underlying ns3 TraceSource - * exporting a packet, an IPv4 object, and an interface. This probe - * exports a trace source "Output" with arguments of type Ptr, - * Ptr, and uint32_t. The Output trace source emits a value - * when either the trace source emits a new value, or when SetValue () + * This class is designed to probe an underlying ns3 TraceSource exporting + * an IPv4 header, a packet, an IPv4 object, and an interface. This probe + * exports a trace source "Output" with arguments of type const Ipv4Header&, + * Ptr, Ptr, and uint32_t. The Output trace source emits + * a value when either the trace source emits a new value, or when SetValue () * is called. */ class Ipv4PacketProbe : public Probe @@ -58,21 +59,23 @@ class Ipv4PacketProbe : public Probe /** * \brief Set a probe value * + * \param header set the Ipv4 header equal to this * \param packet set the traced packet equal to this * \param ipv4 set the IPv4 object for the traced packet equal to this * \param interface set the IPv4 interface for the traced packet equal to this */ - void SetValue (Ptr packet, Ptr ipv4, uint32_t interface); + void SetValue (const Ipv4Header & header, Ptr packet, Ptr ipv4, uint32_t interface); /** * \brief Set a probe value by its name in the Config system * * \param path config path to access the probe + * \param header set the Ipv4 header equal to this * \param packet set the traced packet equal to this * \param ipv4 set the IPv4 object for the traced packet equal to this * \param interface set the IPv4 interface for the traced packet equal to this */ - static void SetValueByPath (std::string path, Ptr packet, Ptr ipv4, uint32_t interface); + static void SetValueByPath (std::string path, const Ipv4Header & header, Ptr packet, Ptr ipv4, uint32_t interface); /** * \brief connect to a trace source attribute provided by a given object @@ -95,20 +98,24 @@ class Ipv4PacketProbe : public Probe private: /** - * \brief Method to connect to an underlying ns3::TraceSource with - * arguments of type Ptr, Ptr, and uint32_t + * \brief Method to connect to an underlying ns3::TraceSource with arguments + * of type const Ipv4Header&, Ptr, Ptr, and uint32_t * + * \param header the Ipv4 header of the traced packet * \param packet the traced packet * \param ipv4 the IPv4 object for the traced packet * \param interface the IPv4 interface for the traced packet */ - void TraceSink (Ptr packet, Ptr ipv4, uint32_t interface); + void TraceSink (const Ipv4Header & header, Ptr packet, Ptr ipv4, uint32_t interface); - /// Traced Callback: the packet, the Ipv4 object and the interface. - ns3::TracedCallback, Ptr, uint32_t> m_output; + /// Traced Callback: the Ipv4 header, the packet, the Ipv4 object and the interface. + ns3::TracedCallback, Ptr, uint32_t> m_output; /// Traced Callback: the previous packet's size and the actual packet's size. ns3::TracedCallback m_outputBytes; + /// The traced IPv4 header. + Ipv4Header m_header; + /// The traced packet. Ptr m_packet; diff --git a/src/internet/model/ipv6-extension.cc b/src/internet/model/ipv6-extension.cc index e20c986a207..d1c91dfcf37 100644 --- a/src/internet/model/ipv6-extension.cc +++ b/src/internet/model/ipv6-extension.cc @@ -421,13 +421,10 @@ uint8_t Ipv6ExtensionFragment::Process (Ptr& packet, return 0; } -void Ipv6ExtensionFragment::GetFragments (Ptr packet, uint32_t maxFragmentSize, std::list >& listFragments) +void Ipv6ExtensionFragment::GetFragments (Ptr packet, Ipv6Header ipv6Header, uint32_t maxFragmentSize, std::list& listFragments) { Ptr p = packet->Copy (); - Ipv6Header ipv6Header; - p->RemoveHeader (ipv6Header); - uint8_t nextHeader = ipv6Header.GetNextHeader (); uint8_t ipv6HeaderSize = ipv6Header.GetSerializedSize (); @@ -579,11 +576,12 @@ void Ipv6ExtensionFragment::GetFragments (Ptr packet, uint32_t maxFragme } ipv6Header.SetPayloadLength (fragment->GetSize ()); - fragment->AddHeader (ipv6Header); std::ostringstream oss; + oss << ipv6Header; fragment->Print (oss); - listFragments.push_back (fragment); + + listFragments.push_back (PacketWithHeader (fragment, ipv6Header)); } while (moreFragment); diff --git a/src/internet/model/ipv6-extension.h b/src/internet/model/ipv6-extension.h index 9df36db383d..7cf5c9a1833 100644 --- a/src/internet/model/ipv6-extension.h +++ b/src/internet/model/ipv6-extension.h @@ -285,13 +285,18 @@ class Ipv6ExtensionFragment : public Ipv6Extension bool& isDropped, Ipv6L3Protocol::DropReason& dropReason); + /** + * \brief Pair of a packet and an Ipv6 header. + */ + typedef std::pair, Ipv6Header> PacketWithHeader; + /** * \brief Fragment a packet * \param packet the packet * \param fragmentSize the maximal size of the fragment (unfragmentable part + fragmentation header + fragmentable part) * \param listFragments the list of fragments */ - void GetFragments (Ptr packet, uint32_t fragmentSize, std::list >& listFragments); + void GetFragments (Ptr packet, Ipv6Header ipv6Header, uint32_t fragmentSize, std::list& listFragments); protected: /** diff --git a/src/internet/model/ipv6-interface.cc b/src/internet/model/ipv6-interface.cc index ada62b06ad7..ef26165f03a 100644 --- a/src/internet/model/ipv6-interface.cc +++ b/src/internet/model/ipv6-interface.cc @@ -30,6 +30,7 @@ #include "ipv6-l3-protocol.h" #include "icmpv6-l4-protocol.h" #include "ndisc-cache.h" +#include "ns3/traffic-control-layer.h" namespace ns3 { @@ -369,22 +370,28 @@ Ipv6InterfaceAddress Ipv6Interface::GetAddressMatchingDestination (Ipv6Address d return ret; /* quiet compiler */ } -void Ipv6Interface::Send (Ptr p, Ipv6Address dest) +void Ipv6Interface::Send (Ptr p, const Ipv6Header & hdr, Ipv6Address dest) { NS_LOG_FUNCTION (this << p << dest); - Ptr ipv6 = m_node->GetObject (); if (!IsUp ()) { return; } - /* check if destination is localhost (::1) */ + Ptr ipv6 = m_node->GetObject (); + Ptr tc = m_node->GetObject (); + + NS_ASSERT (tc != 0); + + /* check if destination is localhost (::1), if yes we don't pass through + * traffic control layer */ if (DynamicCast (m_device)) { /** \todo additional checks needed here (such as whether multicast * goes to loopback)? */ + p->AddHeader (hdr); m_device->Send (p, m_device->GetBroadcast (), Ipv6L3Protocol::PROT_NUMBER); return; } @@ -394,11 +401,11 @@ void Ipv6Interface::Send (Ptr p, Ipv6Address dest) { if (dest == it->first.GetAddress ()) { - ipv6->Receive (m_device, p, Ipv6L3Protocol::PROT_NUMBER, - m_device->GetBroadcast (), - m_device->GetBroadcast (), - NetDevice::PACKET_HOST // note: linux uses PACKET_LOOPBACK here - ); + p->AddHeader (hdr); + tc->Receive (m_device, p, Ipv6L3Protocol::PROT_NUMBER, + m_device->GetBroadcast (), + m_device->GetBroadcast (), + NetDevice::PACKET_HOST); return; } } @@ -424,19 +431,19 @@ void Ipv6Interface::Send (Ptr p, Ipv6Address dest) else { NS_LOG_LOGIC ("NDISC Lookup"); - found = icmpv6->Lookup (p, dest, GetDevice (), m_ndCache, &hardwareDestination); + found = icmpv6->Lookup (p, hdr, dest, GetDevice (), m_ndCache, &hardwareDestination); } if (found) { NS_LOG_LOGIC ("Address Resolved. Send."); - m_device->Send (p, hardwareDestination, Ipv6L3Protocol::PROT_NUMBER); + tc->Send (m_device, p, hdr, hardwareDestination, Ipv6L3Protocol::PROT_NUMBER); } } else { NS_LOG_LOGIC ("Doesn't need ARP"); - m_device->Send (p, m_device->GetBroadcast (), Ipv6L3Protocol::PROT_NUMBER); + tc->Send (m_device, p, hdr, m_device->GetBroadcast (), Ipv6L3Protocol::PROT_NUMBER); } } diff --git a/src/internet/model/ipv6-interface.h b/src/internet/model/ipv6-interface.h index e5a088344b7..cdd0248ead3 100644 --- a/src/internet/model/ipv6-interface.h +++ b/src/internet/model/ipv6-interface.h @@ -23,7 +23,7 @@ #include -#include "ns3/ipv6-address.h" +#include "ns3/ipv6-header.h" #include "ns3/ipv6-interface-address.h" #include "ns3/ptr.h" #include "ns3/object.h" @@ -180,12 +180,13 @@ class Ipv6Interface : public Object /** * \brief Send a packet through this interface. * \param p packet to send + * \param hdr IPv6 header * \param dest next hop address of packet. * * \note This method will eventually call the private SendTo * method which must be implemented by subclasses. */ - void Send (Ptr p, Ipv6Address dest); + void Send (Ptr p, const Ipv6Header & hdr, Ipv6Address dest); /** * \brief Add an IPv6 address. diff --git a/src/internet/model/ipv6-l3-protocol.cc b/src/internet/model/ipv6-l3-protocol.cc index dcf591ec66f..80d17e9ef1c 100644 --- a/src/internet/model/ipv6-l3-protocol.cc +++ b/src/internet/model/ipv6-l3-protocol.cc @@ -30,6 +30,7 @@ #include "ns3/ipv6-route.h" #include "ns3/mac16-address.h" #include "ns3/mac64-address.h" +#include "ns3/traffic-control-layer.h" #include "loopback-net-device.h" #include "ipv6-l3-protocol.h" @@ -189,10 +190,18 @@ Ptr Ipv6L3Protocol::GetRoutingProtocol () const uint32_t Ipv6L3Protocol::AddInterface (Ptr device) { NS_LOG_FUNCTION (this << device); - Ptr node = GetObject (); Ptr interface = CreateObject (); - node->RegisterProtocolHandler (MakeCallback (&Ipv6L3Protocol::Receive, this), Ipv6L3Protocol::PROT_NUMBER, device); + Ptr tc = m_node->GetObject (); + + NS_ASSERT (tc != 0); + + m_node->RegisterProtocolHandler (MakeCallback (&TrafficControlLayer::Receive, tc), + Ipv6L3Protocol::PROT_NUMBER, device); + + tc->RegisterProtocolHandler (MakeCallback (&Ipv6L3Protocol::Receive, this), + Ipv6L3Protocol::PROT_NUMBER, device); + interface->SetNode (m_node); interface->SetDevice (device); interface->SetForwarding (m_ipForward); @@ -948,7 +957,6 @@ void Ipv6L3Protocol::Receive (Ptr device, Ptr p, uint16 { if (ipv6Interface->IsUp ()) { - m_rxTrace (packet, m_node->GetObject (), interface); break; } else @@ -965,6 +973,7 @@ void Ipv6L3Protocol::Receive (Ptr device, Ptr p, uint16 Ipv6Header hdr; packet->RemoveHeader (hdr); + m_rxTrace (hdr, packet, m_node->GetObject (), interface); // Trim any residual frame padding from underlying devices if (hdr.GetPayloadLength () < packet->GetSize ()) @@ -1086,7 +1095,7 @@ void Ipv6L3Protocol::SendRealOut (Ptr route, Ptr packet, Ipv6 NS_LOG_LOGIC ("Send via NetDevice ifIndex " << dev->GetIfIndex () << " Ipv6InterfaceIndex " << interface); // Check packet size - std::list > fragments; + std::list fragments; // Check if we have a Path MTU stored. If so, use it. Else, use the link MTU. size_t targetMtu = (size_t)(m_pmtuCache->GetPmtu (ipHeader.GetDestinationAddress())); @@ -1124,12 +1133,10 @@ void Ipv6L3Protocol::SendRealOut (Ptr route, Ptr packet, Ipv6 Ptr ipv6ExtensionDemux = m_node->GetObject (); - packet->AddHeader (ipHeader); - // To get specific method GetFragments from Ipv6ExtensionFragmentation Ipv6ExtensionFragment *ipv6Fragment = dynamic_cast (PeekPointer (ipv6ExtensionDemux->GetExtension (Ipv6Header::IPV6_EXT_FRAGMENTATION))); NS_ASSERT (ipv6Fragment != 0); - ipv6Fragment->GetFragments (packet, targetMtu, fragments); + ipv6Fragment->GetFragments (packet, ipHeader, targetMtu, fragments); } if (!route->GetGateway ().IsEqual (Ipv6Address::GetAny ())) @@ -1142,18 +1149,16 @@ void Ipv6L3Protocol::SendRealOut (Ptr route, Ptr packet, Ipv6 { std::ostringstream oss; - /* IPv6 header is already added in fragments */ - for (std::list >::const_iterator it = fragments.begin (); it != fragments.end (); it++) + for (std::list::const_iterator it = fragments.begin (); it != fragments.end (); it++) { - m_txTrace (*it, m_node->GetObject (), interface); - outInterface->Send (*it, route->GetGateway ()); + m_txTrace (it->second, it->first, m_node->GetObject (), interface); + outInterface->Send (it->first, it->second, route->GetGateway ()); } } else { - packet->AddHeader (ipHeader); - m_txTrace (packet, m_node->GetObject (), interface); - outInterface->Send (packet, route->GetGateway ()); + m_txTrace (ipHeader, packet, m_node->GetObject (), interface); + outInterface->Send (packet, ipHeader, route->GetGateway ()); } } else @@ -1172,18 +1177,16 @@ void Ipv6L3Protocol::SendRealOut (Ptr route, Ptr packet, Ipv6 { std::ostringstream oss; - /* IPv6 header is already added in fragments */ - for (std::list >::const_iterator it = fragments.begin (); it != fragments.end (); it++) + for (std::list::const_iterator it = fragments.begin (); it != fragments.end (); it++) { - m_txTrace (*it, m_node->GetObject (), interface); - outInterface->Send (*it, ipHeader.GetDestinationAddress ()); + m_txTrace (it->second, it->first, m_node->GetObject (), interface); + outInterface->Send (it->first, it->second, ipHeader.GetDestinationAddress ()); } } else { - packet->AddHeader (ipHeader); - m_txTrace (packet, m_node->GetObject (), interface); - outInterface->Send (packet, ipHeader.GetDestinationAddress ()); + m_txTrace (ipHeader, packet, m_node->GetObject (), interface); + outInterface->Send (packet, ipHeader, ipHeader.GetDestinationAddress ()); } } else diff --git a/src/internet/model/ipv6-l3-protocol.h b/src/internet/model/ipv6-l3-protocol.h index 732d08fca14..463a201678e 100644 --- a/src/internet/model/ipv6-l3-protocol.h +++ b/src/internet/model/ipv6-l3-protocol.h @@ -430,6 +430,7 @@ class Ipv6L3Protocol : public Ipv6 /** * TracedCallback signature for packet transmission or reception events. * + * \param [in] header The Ipv6Header. * \param [in] packet The packet. * \param [in] ipv6 * \param [in] interface @@ -437,7 +438,7 @@ class Ipv6L3Protocol : public Ipv6 * and will be changed to \c Ptr in a future release. */ typedef void (* TxRxTracedCallback) - (Ptr packet, Ptr ipv6, uint32_t interface); + (const Ipv6Header & header, Ptr packet, Ptr ipv6, uint32_t interface); /** * TracedCallback signature for packet drop events. @@ -549,14 +550,14 @@ class Ipv6L3Protocol : public Ipv6 * \deprecated The non-const \c Ptr argument is deprecated * and will be changed to \c Ptr in a future release. */ - TracedCallback, Ptr, uint32_t> m_txTrace; + TracedCallback, Ptr, uint32_t> m_txTrace; /** * \brief Callback to trace RX (reception) packets. * \deprecated The non-const \c Ptr argument is deprecated * and will be changed to \c Ptr in a future release. */ - TracedCallback, Ptr, uint32_t> m_rxTrace; + TracedCallback, Ptr, uint32_t> m_rxTrace; /** * \brief Callback to trace drop packets. diff --git a/src/internet/model/ipv6-packet-probe.cc b/src/internet/model/ipv6-packet-probe.cc index 5c5e3d67757..2ad90a8c075 100644 --- a/src/internet/model/ipv6-packet-probe.cc +++ b/src/internet/model/ipv6-packet-probe.cc @@ -70,26 +70,27 @@ Ipv6PacketProbe::~Ipv6PacketProbe () } void -Ipv6PacketProbe::SetValue (Ptr packet, Ptr ipv6, uint32_t interface) +Ipv6PacketProbe::SetValue (const Ipv6Header & header, Ptr packet, Ptr ipv6, uint32_t interface) { - NS_LOG_FUNCTION (this << packet << ipv6 << interface); + NS_LOG_FUNCTION (this << header << packet << ipv6 << interface); + m_header = header; m_packet = packet; m_ipv6 = ipv6; m_interface = interface; - m_output (packet, ipv6, interface); + m_output (header, packet, ipv6, interface); - uint32_t packetSizeNew = packet->GetSize (); + uint32_t packetSizeNew = packet->GetSize () + header.GetSerializedSize (); m_outputBytes (m_packetSizeOld, packetSizeNew); m_packetSizeOld = packetSizeNew; } void -Ipv6PacketProbe::SetValueByPath (std::string path, Ptr packet, Ptr ipv6, uint32_t interface) +Ipv6PacketProbe::SetValueByPath (std::string path, const Ipv6Header & header, Ptr packet, Ptr ipv6, uint32_t interface) { - NS_LOG_FUNCTION (path << packet << ipv6 << interface); + NS_LOG_FUNCTION (path << header << packet << ipv6 << interface); Ptr probe = Names::Find (path); NS_ASSERT_MSG (probe, "Error: Can't find probe for path " << path); - probe->SetValue (packet, ipv6, interface); + probe->SetValue (header, packet, ipv6, interface); } bool @@ -110,17 +111,18 @@ Ipv6PacketProbe::ConnectByPath (std::string path) } void -Ipv6PacketProbe::TraceSink (Ptr packet, Ptr ipv6, uint32_t interface) +Ipv6PacketProbe::TraceSink (const Ipv6Header & header, Ptr packet, Ptr ipv6, uint32_t interface) { - NS_LOG_FUNCTION (this << packet << ipv6 << interface); + NS_LOG_FUNCTION (this << header << packet << ipv6 << interface); if (IsEnabled ()) { + m_header = header; m_packet = packet; m_ipv6 = ipv6; m_interface = interface; - m_output (packet, ipv6, interface); + m_output (header, packet, ipv6, interface); - uint32_t packetSizeNew = packet->GetSize (); + uint32_t packetSizeNew = packet->GetSize () + header.GetSerializedSize (); m_outputBytes (m_packetSizeOld, packetSizeNew); m_packetSizeOld = packetSizeNew; } diff --git a/src/internet/model/ipv6-packet-probe.h b/src/internet/model/ipv6-packet-probe.h index d86199cb98a..badc6658b99 100644 --- a/src/internet/model/ipv6-packet-probe.h +++ b/src/internet/model/ipv6-packet-probe.h @@ -31,6 +31,7 @@ #include "ns3/nstime.h" #include "ns3/packet.h" #include "ns3/ipv6.h" +#include "ns3/ipv6-header.h" #include "ns3/traced-value.h" #include "ns3/simulator.h" #include "ns3/probe.h" @@ -38,11 +39,11 @@ namespace ns3 { /** - * This class is designed to probe an underlying ns3 TraceSource - * exporting a packet, an IPv6 object, and an interface. This probe - * exports a trace source "Output" with arguments of type Ptr, - * Ptr, and uint32_t. The Output trace source emits a value - * when either the trace source emits a new value, or when SetValue () + * This class is designed to probe an underlying ns3 TraceSource exporting + * an IPv6 header, a packet, an IPv6 object, and an interface. This probe + * exports a trace source "Output" with arguments of type const Ipv6Header&, + * Ptr, Ptr, and uint32_t. The Output trace source emits + * a value when either the trace source emits a new value, or when SetValue () * is called. */ class Ipv6PacketProbe : public Probe @@ -60,21 +61,23 @@ class Ipv6PacketProbe : public Probe /** * \brief Set a probe value * + * \param header set the Ipv6 header equal to this * \param packet set the traced packet equal to this * \param ipv6 set the IPv6 object for the traced packet equal to this * \param interface set the IPv6 interface for the traced packet equal to this */ - void SetValue (Ptr packet, Ptr ipv6, uint32_t interface); + void SetValue (const Ipv6Header & header, Ptr packet, Ptr ipv6, uint32_t interface); /** * \brief Set a probe value by its name in the Config system * * \param path config path to access the probe + * \param header set the Ipv6 header equal to this * \param packet set the traced packet equal to this * \param ipv6 set the IPv6 object for the traced packet equal to this * \param interface set the IPv6 interface for the traced packet equal to this */ - static void SetValueByPath (std::string path, Ptr packet, Ptr ipv6, uint32_t interface); + static void SetValueByPath (std::string path, const Ipv6Header & header, Ptr packet, Ptr ipv6, uint32_t interface); /** * \brief connect to a trace source attribute provided by a given object @@ -97,20 +100,24 @@ class Ipv6PacketProbe : public Probe private: /** - * \brief Method to connect to an underlying ns3::TraceSource with - * arguments of type Ptr, Ptr, and uint32_t + * \brief Method to connect to an underlying ns3::TraceSource with arguments + * of type const Ipv6Header&, Ptr, Ptr, and uint32_t * + * \param header the Ipv6 header of the traced packet * \param packet the traced packet * \param ipv6 the IPv6 object for the traced packet * \param interface the IPv6 interface for the traced packet */ - void TraceSink (Ptr packet, Ptr ipv6, uint32_t interface); + void TraceSink (const Ipv6Header & header, Ptr packet, Ptr ipv6, uint32_t interface); - /// Traced Callback: the packet, the Ipv6 object and the interface. - ns3::TracedCallback, Ptr, uint32_t> m_output; + /// Traced Callback: the Ipv6 header, the packet, the Ipv6 object and the interface. + ns3::TracedCallback, Ptr, uint32_t> m_output; /// Traced Callback: the previous packet's size and the actual packet's size. ns3::TracedCallback m_outputBytes; + /// The traced IPv6 header. + Ipv6Header m_header; + /// The traced packet. Ptr m_packet; diff --git a/src/internet/model/ndisc-cache.cc b/src/internet/model/ndisc-cache.cc index 5a9dc0c27d3..54e12a86e08 100644 --- a/src/internet/model/ndisc-cache.cc +++ b/src/internet/model/ndisc-cache.cc @@ -217,15 +217,15 @@ bool NdiscCache::Entry::IsRouter () const return m_router; } -void NdiscCache::Entry::AddWaitingPacket (Ptr p) +void NdiscCache::Entry::AddWaitingPacket (PacketWithHeader p) { - NS_LOG_FUNCTION (this << p); + NS_LOG_FUNCTION (this << p.second << p.first); if (m_waiting.size () >= m_ndCache->GetUnresQlen ()) { /* we store only m_unresQlen packet => first packet in first packet remove */ /** \todo report packet as 'dropped' */ - m_waiting.remove (0); + // m_waiting.remove (0); } m_waiting.push_back (p); } @@ -276,13 +276,17 @@ void NdiscCache::Entry::FunctionRetransmitTimeout () } else { - Ptr malformedPacket = m_waiting.front (); - if (malformedPacket == 0) + PacketWithHeader malformedPacket = m_waiting.front (); + if (malformedPacket.first == 0) { - malformedPacket = Create (); + malformedPacket.first = Create (); + } + else + { + malformedPacket.first->AddHeader (malformedPacket.second); } - icmpv6->SendErrorDestinationUnreachable (malformedPacket, addr, Icmpv6Header::ICMPV6_ADDR_UNREACHABLE); + icmpv6->SendErrorDestinationUnreachable (malformedPacket.first, addr, Icmpv6Header::ICMPV6_ADDR_UNREACHABLE); /* delete the entry */ m_ndCache->Remove (this); @@ -318,8 +322,9 @@ void NdiscCache::Entry::FunctionDelayTimeout () return; } - Ptr p = icmpv6->ForgeNS (addr, m_ipv6Address, m_ipv6Address, m_ndCache->GetDevice ()->GetAddress ()); - m_ndCache->GetDevice ()->Send (p, this->GetMacAddress (), Ipv6L3Protocol::PROT_NUMBER); + PacketWithHeader p = icmpv6->ForgeNS (addr, m_ipv6Address, m_ipv6Address, m_ndCache->GetDevice ()->GetAddress ()); + p.first->AddHeader (p.second); + m_ndCache->GetDevice ()->Send (p.first, this->GetMacAddress (), Ipv6L3Protocol::PROT_NUMBER); m_nsRetransmit = 1; StartProbeTimer (); @@ -358,8 +363,9 @@ void NdiscCache::Entry::FunctionProbeTimeout () } /* icmpv6->SendNS (m_ndCache->GetInterface ()->GetLinkLocalAddress (), m_ipv6Address, m_ipv6Address, m_ndCache->GetDevice ()->GetAddress ()); */ - Ptr p = icmpv6->ForgeNS (addr, m_ipv6Address, m_ipv6Address, m_ndCache->GetDevice ()->GetAddress ()); - m_ndCache->GetDevice ()->Send (p, this->GetMacAddress (), Ipv6L3Protocol::PROT_NUMBER); + PacketWithHeader p = icmpv6->ForgeNS (addr, m_ipv6Address, m_ipv6Address, m_ndCache->GetDevice ()->GetAddress ()); + p.first->AddHeader (p.second); + m_ndCache->GetDevice ()->Send (p.first, this->GetMacAddress (), Ipv6L3Protocol::PROT_NUMBER); /* arm the timer again */ StartProbeTimer (); @@ -444,18 +450,18 @@ void NdiscCache::Entry::StopNudTimer () m_nsRetransmit = 0; } -void NdiscCache::Entry::MarkIncomplete (Ptr p) +void NdiscCache::Entry::MarkIncomplete (PacketWithHeader p) { - NS_LOG_FUNCTION (this << p); + NS_LOG_FUNCTION (this << p.second << p.first); m_state = INCOMPLETE; - if (p) + if (p.first) { m_waiting.push_back (p); } } -std::list > NdiscCache::Entry::MarkReachable (Address mac) +std::list NdiscCache::Entry::MarkReachable (Address mac) { NS_LOG_FUNCTION (this << mac); m_state = REACHABLE; @@ -481,7 +487,7 @@ void NdiscCache::Entry::MarkReachable () m_state = REACHABLE; } -std::list > NdiscCache::Entry::MarkStale (Address mac) +std::list NdiscCache::Entry::MarkStale (Address mac) { NS_LOG_FUNCTION (this << mac); m_state = STALE; diff --git a/src/internet/model/ndisc-cache.h b/src/internet/model/ndisc-cache.h index 81eca932971..6e1341e20f6 100644 --- a/src/internet/model/ndisc-cache.h +++ b/src/internet/model/ndisc-cache.h @@ -38,6 +38,7 @@ namespace ns3 class NetDevice; class Ipv6Interface; +class Ipv6Header; /** * \class NdiscCache @@ -131,6 +132,11 @@ class NdiscCache : public Object */ void PrintNdiscCache (Ptr stream); + /** + * \brief Pair of a packet and an Ipv4 header. + */ + typedef std::pair, Ipv6Header> PacketWithHeader; + /** * \class Entry * \brief A record that holds information about an NdiscCache entry. @@ -148,14 +154,14 @@ class NdiscCache : public Object * \brief Changes the state to this entry to INCOMPLETE. * \param p packet that wait to be sent */ - void MarkIncomplete (Ptr p); + void MarkIncomplete (PacketWithHeader p); /** * \brief Changes the state to this entry to REACHABLE. * \param mac MAC address * \return the list of packet waiting */ - std::list > MarkReachable (Address mac); + std::list MarkReachable (Address mac); /** * \brief Changes the state to this entry to PROBE. @@ -167,7 +173,7 @@ class NdiscCache : public Object * \param mac L2 address * \return the list of packet waiting */ - std::list > MarkStale (Address mac); + std::list MarkStale (Address mac); /** * \brief Changes the state to this entry to STALE. @@ -188,7 +194,7 @@ class NdiscCache : public Object * \brief Add a packet (or replace old value) in the queue. * \param p packet to add */ - void AddWaitingPacket (Ptr p); + void AddWaitingPacket (PacketWithHeader p); /** * \brief Clear the waiting packet list. @@ -349,7 +355,7 @@ class NdiscCache : public Object /** * \brief The list of packet waiting. */ - std::list > m_waiting; + std::list m_waiting; /** * \brief Type of node (router or host). diff --git a/src/internet/test/codel-queue-test-suite.cc b/src/internet/test/codel-queue-test-suite.cc index c96388619cd..5f7cf29d0e7 100644 --- a/src/internet/test/codel-queue-test-suite.cc +++ b/src/internet/test/codel-queue-test-suite.cc @@ -125,55 +125,55 @@ CoDelQueueBasicEnqueueDequeue::DoRun (void) p6 = Create (pktSize); QueueTestSize (queue, 0 * modeSize, "There should be no packets in queue"); - queue->Enqueue (p1); + queue->Enqueue (Create (p1)); QueueTestSize (queue, 1 * modeSize, "There should be one packet in queue"); - queue->Enqueue (p2); + queue->Enqueue (Create (p2)); QueueTestSize (queue, 2 * modeSize, "There should be two packets in queue"); - queue->Enqueue (p3); + queue->Enqueue (Create (p3)); QueueTestSize (queue, 3 * modeSize, "There should be three packets in queue"); - queue->Enqueue (p4); + queue->Enqueue (Create (p4)); QueueTestSize (queue, 4 * modeSize, "There should be four packets in queue"); - queue->Enqueue (p5); + queue->Enqueue (Create (p5)); QueueTestSize (queue, 5 * modeSize, "There should be five packets in queue"); - queue->Enqueue (p6); + queue->Enqueue (Create (p6)); QueueTestSize (queue, 6 * modeSize, "There should be six packets in queue"); NS_TEST_EXPECT_MSG_EQ (queue->GetDropOverLimit (), 0, "There should be no packets being dropped due to full queue"); - Ptr p; + Ptr item; - p = queue->Dequeue (); - NS_TEST_EXPECT_MSG_EQ ((p != 0), true, "I want to remove the first packet"); + item = queue->Dequeue (); + NS_TEST_EXPECT_MSG_EQ ((item != 0), true, "I want to remove the first packet"); QueueTestSize (queue, 5 * modeSize, "There should be five packets in queue"); - NS_TEST_EXPECT_MSG_EQ (p->GetUid (), p1->GetUid (), "was this the first packet ?"); + NS_TEST_EXPECT_MSG_EQ (item->GetPacket ()->GetUid (), p1->GetUid (), "was this the first packet ?"); - p = queue->Dequeue (); - NS_TEST_EXPECT_MSG_EQ ((p != 0), true, "I want to remove the second packet"); + item = queue->Dequeue (); + NS_TEST_EXPECT_MSG_EQ ((item != 0), true, "I want to remove the second packet"); QueueTestSize (queue, 4 * modeSize, "There should be four packets in queue"); - NS_TEST_EXPECT_MSG_EQ (p->GetUid (), p2->GetUid (), "Was this the second packet ?"); + NS_TEST_EXPECT_MSG_EQ (item->GetPacket ()->GetUid (), p2->GetUid (), "Was this the second packet ?"); - p = queue->Dequeue (); - NS_TEST_EXPECT_MSG_EQ ((p != 0), true, "I want to remove the third packet"); + item = queue->Dequeue (); + NS_TEST_EXPECT_MSG_EQ ((item != 0), true, "I want to remove the third packet"); QueueTestSize (queue, 3 * modeSize, "There should be three packets in queue"); - NS_TEST_EXPECT_MSG_EQ (p->GetUid (), p3->GetUid (), "Was this the third packet ?"); + NS_TEST_EXPECT_MSG_EQ (item->GetPacket ()->GetUid (), p3->GetUid (), "Was this the third packet ?"); - p = queue->Dequeue (); - NS_TEST_EXPECT_MSG_EQ ((p != 0), true, "I want to remove the forth packet"); + item = queue->Dequeue (); + NS_TEST_EXPECT_MSG_EQ ((item != 0), true, "I want to remove the forth packet"); QueueTestSize (queue, 2 * modeSize, "There should be two packets in queue"); - NS_TEST_EXPECT_MSG_EQ (p->GetUid (), p4->GetUid (), "Was this the fourth packet ?"); + NS_TEST_EXPECT_MSG_EQ (item->GetPacket ()->GetUid (), p4->GetUid (), "Was this the fourth packet ?"); - p = queue->Dequeue (); - NS_TEST_EXPECT_MSG_EQ ((p != 0), true, "I want to remove the fifth packet"); + item = queue->Dequeue (); + NS_TEST_EXPECT_MSG_EQ ((item != 0), true, "I want to remove the fifth packet"); QueueTestSize (queue, 1 * modeSize, "There should be one packet in queue"); - NS_TEST_EXPECT_MSG_EQ (p->GetUid (), p5->GetUid (), "Was this the fifth packet ?"); + NS_TEST_EXPECT_MSG_EQ (item->GetPacket ()->GetUid (), p5->GetUid (), "Was this the fifth packet ?"); - p = queue->Dequeue (); - NS_TEST_EXPECT_MSG_EQ ((p != 0), true, "I want to remove the last packet"); + item = queue->Dequeue (); + NS_TEST_EXPECT_MSG_EQ ((item != 0), true, "I want to remove the last packet"); QueueTestSize (queue, 0 * modeSize, "There should be zero packet in queue"); - NS_TEST_EXPECT_MSG_EQ (p->GetUid (), p6->GetUid (), "Was this the sixth packet ?"); + NS_TEST_EXPECT_MSG_EQ (item->GetPacket ()->GetUid (), p6->GetUid (), "Was this the sixth packet ?"); - p = queue->Dequeue (); - NS_TEST_EXPECT_MSG_EQ ((p == 0), true, "There are really no packets in queue"); + item = queue->Dequeue (); + NS_TEST_EXPECT_MSG_EQ ((item == 0), true, "There are really no packets in queue"); NS_TEST_EXPECT_MSG_EQ (queue->GetDropCount (), 0, "There should be no packet drops according to CoDel algorithm"); } @@ -242,9 +242,9 @@ CoDelQueueBasicOverflow::DoRun (void) "Verify that we can actually set the attribute MinBytes"); Enqueue (queue, pktSize, 500); - queue->Enqueue (p1); - queue->Enqueue (p2); - queue->Enqueue (p3); + queue->Enqueue (Create (p1)); + queue->Enqueue (Create (p2)); + queue->Enqueue (Create (p3)); QueueTestSize (queue, 500 * modeSize, "There should be 500 packets in queue"); NS_TEST_EXPECT_MSG_EQ (queue->GetDropOverLimit (), 3, "There should be three packets being dropped due to full queue"); @@ -255,7 +255,7 @@ CoDelQueueBasicOverflow::Enqueue (Ptr queue, uint32_t size, uint32_t { for (uint32_t i = 0; i < nPkt; i++) { - queue->Enqueue (Create (size)); + queue->Enqueue (Create (Create (size))); } } @@ -435,7 +435,7 @@ CoDelQueueBasicDrop::Enqueue (Ptr queue, uint32_t size, uint32_t nPk { for (uint32_t i = 0; i < nPkt; i++) { - queue->Enqueue (Create (size)); + queue->Enqueue (Create (Create (size))); } } @@ -455,7 +455,7 @@ CoDelQueueBasicDrop::Dequeue (Ptr queue, uint32_t modeSize) if (initialQSize != 0) { - Ptr p = queue->Dequeue (); + Ptr item = queue->Dequeue (); if (initialDropCount == 0 && currentTime > queue->GetTarget ()) { if (currentTime < queue->GetInterval ()) diff --git a/src/internet/test/ipv4-forwarding-test.cc b/src/internet/test/ipv4-forwarding-test.cc index 3200572ef7e..f8895783068 100644 --- a/src/internet/test/ipv4-forwarding-test.cc +++ b/src/internet/test/ipv4-forwarding-test.cc @@ -1,7 +1,7 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Copyright (c) 2013 Universita' di Firenze - * + * * 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; @@ -38,6 +38,8 @@ #include "ns3/udp-l4-protocol.h" #include "ns3/ipv4-static-routing.h" +#include "ns3/traffic-control-layer.h" + #include #include @@ -62,6 +64,9 @@ AddInternetStack (Ptr node) //UDP Ptr udp = CreateObject (); node->AggregateObject (udp); + //Traffic Control + Ptr tc = CreateObject (); + node->AggregateObject (tc); } @@ -79,7 +84,7 @@ class Ipv4ForwardingTest : public TestCase }; Ipv4ForwardingTest::Ipv4ForwardingTest () - : TestCase ("UDP socket implementation") + : TestCase ("UDP socket implementation") { } diff --git a/src/internet/test/ipv4-header-test.cc b/src/internet/test/ipv4-header-test.cc index 5dfa9597b78..e3788aa3818 100644 --- a/src/internet/test/ipv4-header-test.cc +++ b/src/internet/test/ipv4-header-test.cc @@ -1,7 +1,7 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Copyright (c) 2010 Hajime Tazaki - * + * * 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; @@ -38,6 +38,7 @@ #include "ns3/icmpv4-l4-protocol.h" #include "ns3/ipv4-list-routing.h" #include "ns3/ipv4-static-routing.h" +#include "ns3/traffic-control-layer.h" #include #include @@ -67,7 +68,10 @@ AddInternetStack (Ptr node) node->AggregateObject (icmp); // //Ipv4Raw // Ptr udp = CreateObject (); - // node->AggregateObject(udp); + // node->AggregateObject(udp); + // Traffic Control + Ptr tc = CreateObject (); + node->AggregateObject (tc); } @@ -88,7 +92,7 @@ class Ipv4HeaderTest : public TestCase Ipv4HeaderTest::Ipv4HeaderTest () - : TestCase ("IPv4 Header Test") + : TestCase ("IPv4 Header Test") { } @@ -231,7 +235,7 @@ Ipv4HeaderTest::DoRun (void) m_receivedPacket->RemoveAllByteTags (); m_receivedPacket = 0; } - + // Ecn tests std::cout << "Ecn Test\n"; std::vector vEcnTypes; @@ -239,7 +243,7 @@ Ipv4HeaderTest::DoRun (void) vEcnTypes.push_back (Ipv4Header::ECN_ECT1); vEcnTypes.push_back (Ipv4Header::ECN_ECT0); vEcnTypes.push_back (Ipv4Header::ECN_CE); - + for (uint32_t i = 0; i < vEcnTypes.size (); i++) { SendData_IpHdr_Dscp (txSocket, "10.0.0.1", Ipv4Header::DscpDefault, vEcnTypes [i]); @@ -252,7 +256,7 @@ Ipv4HeaderTest::DoRun (void) } - + Simulator::Destroy (); } //----------------------------------------------------------------------------- diff --git a/src/internet/test/ipv4-packet-info-tag-test-suite.cc b/src/internet/test/ipv4-packet-info-tag-test-suite.cc index 9d112a4c523..abf5cdc9821 100644 --- a/src/internet/test/ipv4-packet-info-tag-test-suite.cc +++ b/src/internet/test/ipv4-packet-info-tag-test-suite.cc @@ -45,6 +45,7 @@ #include "ns3/ipv4-list-routing.h" #include "ns3/udp-l4-protocol.h" #include "ns3/tcp-l4-protocol.h" +#include "ns3/traffic-control-layer.h" #include "ns3/simulator.h" #include "ns3/node.h" @@ -72,6 +73,9 @@ AddInternetStack (Ptr node) //UDP Ptr udp = CreateObject (); node->AggregateObject (udp); + // Traffic Control + Ptr tc = CreateObject (); + node->AggregateObject (tc); } } @@ -87,7 +91,7 @@ class Ipv4PacketInfoTagTest : public TestCase }; Ipv4PacketInfoTagTest::Ipv4PacketInfoTagTest () - : TestCase ("Ipv4PacketInfoTagTest") + : TestCase ("Ipv4PacketInfoTagTest") { } @@ -164,7 +168,7 @@ Ipv4PacketInfoTagTest::DoRun (void) socket->SetRecvPktInfo (true); socket->SetRecvCallback (MakeCallback (&Ipv4PacketInfoTagTest::RxCb, this)); - // receive on loopback + // receive on loopback Simulator::ScheduleWithContext (socket->GetNode ()->GetId (), Seconds (0), &Ipv4PacketInfoTagTest::DoSendData, this, socket, "127.0.0.1"); Simulator::Run (); @@ -183,7 +187,7 @@ Ipv4PacketInfoTagTest::DoRun (void) socket->SetRecvPktInfo (true); socket->SetRecvCallback (MakeCallback (&Ipv4PacketInfoTagTest::RxCb, this)); - // receive on loopback + // receive on loopback Simulator::ScheduleWithContext (socket->GetNode ()->GetId (), Seconds (0), &Ipv4PacketInfoTagTest::DoSendData, this, socket, "127.0.0.1"); Simulator::Run (); diff --git a/src/internet/test/ipv6-dual-stack-test-suite.cc b/src/internet/test/ipv6-dual-stack-test-suite.cc index 67ca416c2e6..478dfe56ca3 100644 --- a/src/internet/test/ipv6-dual-stack-test-suite.cc +++ b/src/internet/test/ipv6-dual-stack-test-suite.cc @@ -2,7 +2,7 @@ /* * Copyright (c) 2007 Georgia Tech Research Corporation * Copyright (c) 2009 INRIA - * + * * 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; @@ -44,6 +44,7 @@ #include "ns3/icmpv6-l4-protocol.h" #include "ns3/udp-l4-protocol.h" #include "ns3/tcp-l4-protocol.h" +#include "ns3/traffic-control-layer.h" #include @@ -132,6 +133,10 @@ CreateDualStackNode () ipv6->RegisterExtensions (); ipv6->RegisterOptions (); + // Traffic Control + Ptr tc = CreateObject (); + node->AggregateObject (tc); + return node; } diff --git a/src/internet/test/ipv6-fragmentation-test.cc b/src/internet/test/ipv6-fragmentation-test.cc index ef7d95ef7d3..42d9198862f 100644 --- a/src/internet/test/ipv6-fragmentation-test.cc +++ b/src/internet/test/ipv6-fragmentation-test.cc @@ -55,6 +55,7 @@ #include "ns3/ipv6-l3-protocol.h" #include "ns3/icmpv6-l4-protocol.h" +#include "ns3/traffic-control-layer.h" #include #include @@ -108,6 +109,10 @@ AddInternetStack (Ptr node) //UDP Ptr udp = CreateObject (); node->AggregateObject (udp); + + // Traffic Control + Ptr tc = CreateObject (); + node->AggregateObject (tc); } diff --git a/src/internet/test/ipv6-packet-info-tag-test-suite.cc b/src/internet/test/ipv6-packet-info-tag-test-suite.cc index 92a1c640a2d..97ffe1d3fbc 100644 --- a/src/internet/test/ipv6-packet-info-tag-test-suite.cc +++ b/src/internet/test/ipv6-packet-info-tag-test-suite.cc @@ -44,6 +44,7 @@ #include "ns3/uinteger.h" #include "ns3/boolean.h" #include "ns3/node.h" +#include "ns3/traffic-control-layer.h" using namespace ns3; @@ -66,6 +67,10 @@ AddInternetStack (Ptr node) /* register IPv6 extensions and options */ ipv6->RegisterExtensions (); ipv6->RegisterOptions (); + + // Traffic Control + Ptr tc = CreateObject (); + node->AggregateObject (tc); } class Ipv6PacketInfoTagTest : public TestCase @@ -79,7 +84,7 @@ class Ipv6PacketInfoTagTest : public TestCase }; Ipv6PacketInfoTagTest::Ipv6PacketInfoTagTest () - : TestCase ("Ipv6PacketInfoTagTest") + : TestCase ("Ipv6PacketInfoTagTest") { } @@ -157,7 +162,7 @@ Ipv6PacketInfoTagTest::DoRun (void) socket->SetRecvPktInfo (true); socket->SetRecvCallback (MakeCallback (&Ipv6PacketInfoTagTest::RxCb, this)); - // receive on loopback + // receive on loopback Simulator::ScheduleWithContext (socket->GetNode ()->GetId (), Seconds (0), &Ipv6PacketInfoTagTest::DoSendData, this, socket, "::1"); Simulator::Run (); @@ -167,7 +172,7 @@ Ipv6PacketInfoTagTest::DoRun (void) std::stringstream dst; dst << ifaceAddr1.GetAddress (); Simulator::ScheduleWithContext (socket2->GetNode ()->GetId (), Seconds (0), - &Ipv6PacketInfoTagTest::DoSendData, this, socket, + &Ipv6PacketInfoTagTest::DoSendData, this, socket, dst.str ()); Simulator::Run (); @@ -180,7 +185,7 @@ Ipv6PacketInfoTagTest::DoRun (void) socket->SetRecvPktInfo (true); socket->SetRecvCallback (MakeCallback (&Ipv6PacketInfoTagTest::RxCb, this)); - // receive on loopback + // receive on loopback Simulator::ScheduleWithContext (socket->GetNode ()->GetId (), Seconds (0), &Ipv6PacketInfoTagTest::DoSendData, this, socket, "::1"); Simulator::Run (); diff --git a/src/internet/test/tcp-test.cc b/src/internet/test/tcp-test.cc index e227b52c7d4..1d09f4ed5d7 100644 --- a/src/internet/test/tcp-test.cc +++ b/src/internet/test/tcp-test.cc @@ -2,7 +2,7 @@ /* * Copyright (c) 2007 Georgia Tech Research Corporation * Copyright (c) 2009 INRIA - * + * * 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; @@ -45,6 +45,7 @@ #include "ns3/icmpv6-l4-protocol.h" #include "ns3/udp-l4-protocol.h" #include "ns3/tcp-l4-protocol.h" +#include "ns3/traffic-control-layer.h" #include @@ -101,7 +102,7 @@ static std::string Name (std::string str, uint32_t totalStreamSize, bool useIpv6) { std::ostringstream oss; - oss << str << " total=" << totalStreamSize << " sourceWrite=" << sourceWriteSize + oss << str << " total=" << totalStreamSize << " sourceWrite=" << sourceWriteSize << " sourceRead=" << sourceReadSize << " serverRead=" << serverReadSize << " serverWrite=" << serverWriteSize << " useIpv6=" << useIpv6; return oss.str (); @@ -120,8 +121,8 @@ TcpTestCase::TcpTestCase (uint32_t totalStreamSize, uint32_t serverWriteSize, uint32_t serverReadSize, bool useIpv6) - : TestCase (Name ("Send string data from client to server and back", - totalStreamSize, + : TestCase (Name ("Send string data from client to server and back", + totalStreamSize, sourceWriteSize, serverReadSize, serverWriteSize, @@ -168,9 +169,9 @@ TcpTestCase::DoRun (void) NS_TEST_EXPECT_MSG_EQ (m_currentSourceTxBytes, m_totalBytes, "Source sent all bytes"); NS_TEST_EXPECT_MSG_EQ (m_currentServerRxBytes, m_totalBytes, "Server received all bytes"); NS_TEST_EXPECT_MSG_EQ (m_currentSourceRxBytes, m_totalBytes, "Source received all bytes"); - NS_TEST_EXPECT_MSG_EQ (memcmp (m_sourceTxPayload, m_serverRxPayload, m_totalBytes), 0, + NS_TEST_EXPECT_MSG_EQ (memcmp (m_sourceTxPayload, m_serverRxPayload, m_totalBytes), 0, "Server received expected data buffers"); - NS_TEST_EXPECT_MSG_EQ (memcmp (m_sourceTxPayload, m_sourceRxPayload, m_totalBytes), 0, + NS_TEST_EXPECT_MSG_EQ (memcmp (m_sourceTxPayload, m_sourceRxPayload, m_totalBytes), 0, "Source received back expected data buffers"); } void @@ -200,7 +201,7 @@ TcpTestCase::ServerHandleRecv (Ptr sock) { NS_FATAL_ERROR ("Server could not read stream at byte " << m_currentServerRxBytes); } - NS_TEST_EXPECT_MSG_EQ ((m_currentServerRxBytes + p->GetSize () <= m_totalBytes), true, + NS_TEST_EXPECT_MSG_EQ ((m_currentServerRxBytes + p->GetSize () <= m_totalBytes), true, "Server received too many bytes"); NS_LOG_DEBUG ("Server recv data=\"" << GetString (p) << "\""); p->CopyData (&m_serverRxPayload[m_currentServerRxBytes], p->GetSize ()); @@ -256,7 +257,7 @@ TcpTestCase::SourceHandleRecv (Ptr sock) { NS_FATAL_ERROR ("Source could not read stream at byte " << m_currentSourceRxBytes); } - NS_TEST_EXPECT_MSG_EQ ((m_currentSourceRxBytes + p->GetSize () <= m_totalBytes), true, + NS_TEST_EXPECT_MSG_EQ ((m_currentSourceRxBytes + p->GetSize () <= m_totalBytes), true, "Source received too many bytes"); NS_LOG_DEBUG ("Source recv data=\"" << GetString (p) << "\""); p->CopyData (&m_sourceRxPayload[m_currentSourceRxBytes], p->GetSize ()); @@ -292,6 +293,9 @@ TcpTestCase::CreateInternetNode () //TCP Ptr tcp = CreateObject (); node->AggregateObject (tcp); + // Traffic Control + Ptr tc = CreateObject (); + node->AggregateObject (tc); return node; } @@ -405,6 +409,9 @@ TcpTestCase::CreateInternetNode6 () //TCP Ptr tcp = CreateObject (); node->AggregateObject (tcp); + // Traffic Control + Ptr tc = CreateObject (); + node->AggregateObject (tc); return node; } diff --git a/src/internet/wscript b/src/internet/wscript index 36a39429a44..99ccace695a 100644 --- a/src/internet/wscript +++ b/src/internet/wscript @@ -104,7 +104,7 @@ def configure(conf): def build(bld): # bridge and mpi dependencies are due to global routing - obj = bld.create_ns3_module('internet', ['bridge', 'mpi', 'network', 'core']) + obj = bld.create_ns3_module('internet', ['bridge', 'mpi', 'traffic-control', 'network', 'core']) obj.source = [ 'model/ip-l4-protocol.cc', 'model/udp-header.cc', diff --git a/src/lte/test/epc-test-s1u-uplink.cc b/src/lte/test/epc-test-s1u-uplink.cc index 8499eb35717..fd7b6a0f2dd 100644 --- a/src/lte/test/epc-test-s1u-uplink.cc +++ b/src/lte/test/epc-test-s1u-uplink.cc @@ -399,7 +399,8 @@ EpcS1uUlTestCase::DoRun () Ptr ueArpCache = ueLteIpv4Iface->GetArpCache (); ueArpCache->SetAliveTimeout (Seconds (1000)); ArpCache::Entry* arpCacheEntry = ueArpCache->Add (gwAddr); - arpCacheEntry->MarkWaitReply(0); + Ipv4Header ipHeader; + arpCacheEntry->MarkWaitReply(ArpCache::PacketWithHeader(0, ipHeader)); arpCacheEntry->MarkAlive (Mac48Address::GetBroadcast ()); diff --git a/src/netanim/model/animation-interface.cc b/src/netanim/model/animation-interface.cc index bcd05886b14..a9bbd206736 100644 --- a/src/netanim/model/animation-interface.cc +++ b/src/netanim/model/animation-interface.cc @@ -686,14 +686,14 @@ AnimationInterface::WifiMacRxDropTrace (std::string context, Ptr p } void -AnimationInterface::Ipv4TxTrace (std::string context, Ptr p, Ptr ipv4, uint32_t interfaceIndex) +AnimationInterface::Ipv4TxTrace (std::string context, const Ipv4Header & ipv4Header, Ptr p, Ptr ipv4, uint32_t interfaceIndex) { const Ptr node = GetNodeFromContext (context); ++m_nodeIpv4Tx[node->GetId ()]; } void -AnimationInterface::Ipv4RxTrace (std::string context, Ptr p, Ptr ipv4, uint32_t interfaceIndex) +AnimationInterface::Ipv4RxTrace (std::string context, const Ipv4Header & ipv4Header, Ptr p, Ptr ipv4, uint32_t interfaceIndex) { const Ptr node = GetNodeFromContext (context); ++m_nodeIpv4Rx[node->GetId ()]; diff --git a/src/netanim/model/animation-interface.h b/src/netanim/model/animation-interface.h index 124d0f150b4..173cf28bd5c 100644 --- a/src/netanim/model/animation-interface.h +++ b/src/netanim/model/animation-interface.h @@ -664,9 +664,11 @@ class AnimationInterface void QueueDropTrace (std::string context, Ptr); void Ipv4TxTrace (std::string context, + const Ipv4Header &, Ptr, Ptr, uint32_t); void Ipv4RxTrace (std::string context, + const Ipv4Header &, Ptr, Ptr, uint32_t); void Ipv4DropTrace (std::string context, diff --git a/src/network/model/net-device.cc b/src/network/model/net-device.cc index e854a4fb327..7109059e0cf 100644 --- a/src/network/model/net-device.cc +++ b/src/network/model/net-device.cc @@ -20,6 +20,7 @@ #include "ns3/object.h" #include "ns3/log.h" +#include "ns3/abort.h" #include "ns3/uinteger.h" #include "net-device.h" @@ -27,6 +28,72 @@ namespace ns3 { NS_LOG_COMPONENT_DEFINE ("NetDevice"); +NS_OBJECT_ENSURE_REGISTERED (NetDeviceQueue); + +TypeId NetDeviceQueue::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::NetDeviceQueue") + .SetParent () + .SetGroupName("Network") + ; + return tid; +} + +NetDeviceQueue::NetDeviceQueue() + : m_stopped (false) +{ + NS_LOG_FUNCTION_NOARGS (); +} + +NetDeviceQueue::~NetDeviceQueue () +{ + NS_LOG_FUNCTION (this); +} + +void +NetDeviceQueue::SetDevice (Ptr device) +{ + NS_ABORT_MSG_UNLESS (m_device == 0, "Cannot change the device which a transmission queue belongs to."); + m_device = device; +} + +void +NetDeviceQueue::Start (void) +{ + m_stopped = false; +} + +void +NetDeviceQueue::Stop (void) +{ + m_stopped = true; +} + +void +NetDeviceQueue::Wake (void) +{ + Start (); + + // Request the queue disc to dequeue a packet + if (!m_wakeCallback.IsNull ()) + { + m_wakeCallback (); + } +} + +void +NetDeviceQueue::SetWakeCallback (WakeCallback cb) +{ + m_wakeCallback = cb; +} + +bool +NetDeviceQueue::HasWakeCallbackSet (void) const +{ + return (!m_wakeCallback.IsNull ()); +} + + NS_OBJECT_ENSURE_REGISTERED (NetDevice); TypeId NetDevice::GetTypeId (void) @@ -38,9 +105,49 @@ TypeId NetDevice::GetTypeId (void) return tid; } +NetDevice::NetDevice () +{ + NS_LOG_FUNCTION_NOARGS (); + Ptr devQueue = Create (); + devQueue->SetDevice (this); + m_txQueuesVector.push_back (devQueue); +} + NetDevice::~NetDevice () { NS_LOG_FUNCTION (this); } +uint8_t +NetDevice::GetSelectedQueue (Ptr packet) const +{ + return 0; +} + +void +NetDevice::SetTxQueuesN (uint8_t numTxQueues) +{ + NS_ASSERT (numTxQueues > 0); + + // check whether a queue disc has been aggregated to the device by + // verifying whether a wake callback has been set on a transmission queue + if (GetTxQueue (0)->HasWakeCallbackSet ()) + { + NS_LOG_WARN ("Cannot change the number of transmission queues after installing" + " a queue disc on the device."); + return ; + } + + uint8_t prevNumTxQueues = m_txQueuesVector.size (); + m_txQueuesVector.resize (numTxQueues); + + // Allocate new NetDeviceQueues if the number of queues increased + for (uint8_t i = prevNumTxQueues; i < numTxQueues; i++) + { + Ptr devQueue = Create (); + devQueue->SetDevice (this); + m_txQueuesVector[i] = devQueue; + } +} + } // namespace ns3 diff --git a/src/network/model/net-device.h b/src/network/model/net-device.h index c4599c7a53c..d6602e5e0ab 100644 --- a/src/network/model/net-device.h +++ b/src/network/model/net-device.h @@ -22,6 +22,7 @@ #define NET_DEVICE_H #include +#include #include #include "ns3/callback.h" #include "ns3/object.h" @@ -35,11 +36,102 @@ namespace ns3 { class Node; class Channel; class Packet; +class NetDevice; /** * \ingroup network * \defgroup netdevice Network Device */ +/** + * \ingroup netdevice + * + * \brief Network device transmission queue + * + * This class stores information about a single transmission queue + * of a network device that is exposed to queue discs. Such information + * includes the state of the transmission queue (whether it has been + * stopped or not) and data used by techniques such as Byte Queue Limits. + * Also, multi-queue aware queue discs can aggregate a child queue disc + * to an object of this class. + * + * This class roughly models the struct netdev_queue of Linux. + * \todo Implement BQL + */ +class NetDeviceQueue : public SimpleRefCount +{ +public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + + NetDeviceQueue (); + virtual ~NetDeviceQueue(); + + /** + * \return the device which this transmission queue belongs to. + */ + inline Ptr GetDevice (void) const; + + /** + * \param device the device which this transmission queue belongs to. + * + * The device can be set just once. + */ + virtual void SetDevice (Ptr device); + + /** + * \return true if the (hardware) transmission queue is stopped. + * + * Called by queue discs to enquire about the status of a given transmission queue. + * This is the analogous to the netif_tx_queue_stopped function of the Linux kernel. + */ + inline bool IsStopped (void) const; + + /** + * Called by the device or the stack to start this (hardware) transmission queue. + * This is the analogous to the netif_tx_start_queue function of the Linux kernel. + */ + virtual void Start (void); + + /** + * Called by the device or the stack to stop this (hardware) transmission queue. + * This is the analogous to the netif_tx_stop_queue function of the Linux kernel. + */ + virtual void Stop (void); + + /** + * Called by the device or the stack to wake this (hardware) transmission queue. + * This is the analogous to the netif_tx_wake_queue function of the Linux kernel. + */ + virtual void Wake (void); + + typedef Callback< void > WakeCallback; + + /** + * \param cb callback to invoke whenever it is needed to "wake" the upper layers (i.e., + * solicitate the queue disc aggregated to this transmission queue (in case of + * multi-queue aware queue discs) or to the network device (otherwise) to send + * packets down to the device). + * + * Set the callback to be used to wake the upper layers. + */ + virtual void SetWakeCallback (WakeCallback cb); + + /** + * \return true if the wake callback has been set. + * + * Used to check whether a queue disc has been installed on the device. + */ + virtual bool HasWakeCallbackSet (void) const; + +private: + Ptr m_device; + bool m_stopped; + WakeCallback m_wakeCallback; +}; + /** * \ingroup netdevice * @@ -80,6 +172,8 @@ class NetDevice : public Object * \return the object TypeId */ static TypeId GetTypeId (void); + + NetDevice (); virtual ~NetDevice(); /** @@ -339,8 +433,68 @@ class NetDevice : public Object */ virtual bool SupportsSendFrom (void) const = 0; + /** + * \return the i-th transmission queue of the device. + * + * The index of the first transmission queue is zero. + */ + inline Ptr GetTxQueue (uint8_t i) const; + + /** + * \return the number of (hardware) transmission queues. + */ + inline uint8_t GetTxQueuesN (void) const; + + /** + * \return the id of the transmission queue selected for the given packet + */ + virtual uint8_t GetSelectedQueue (Ptr packet) const; + +protected: + /** + * \param numTxQueues number of (hardware) transmission queues. + * + * Modifying the number of transmission queues is only permitted before a queue + * disc is aggregated to the device. This is because we have to set a wake + * callback for each transmission queue, and this is done when setting up + * queue discs. + */ + virtual void SetTxQueuesN (uint8_t numTxQueues); + +private: + std::vector< Ptr > m_txQueuesVector; }; } // namespace ns3 + +namespace ns3 { + +Ptr +NetDeviceQueue::GetDevice (void) const +{ + return m_device; +} + +bool +NetDeviceQueue::IsStopped (void) const +{ + return m_stopped; +} + +Ptr +NetDevice::GetTxQueue (uint8_t i) const +{ + NS_ASSERT (i < m_txQueuesVector.size ()); + return m_txQueuesVector[i]; +} + +uint8_t +NetDevice::GetTxQueuesN (void) const +{ + return m_txQueuesVector.size (); +} + +} // namespace ns3 + #endif /* NET_DEVICE_H */ diff --git a/src/network/model/node.h b/src/network/model/node.h index ef82159126a..5d066594c36 100644 --- a/src/network/model/node.h +++ b/src/network/model/node.h @@ -202,13 +202,27 @@ class Node : public Object */ void UnregisterDeviceAdditionListener (DeviceAdditionListener listener); - - /** * \returns true if checksums are enabled, false otherwise. */ static bool ChecksumEnabled (void); + /** + * \brief Protocol handler entry. + * This structure is used to demultiplex all the protocols. + */ + struct ProtocolHandlerEntry { + 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; + /// Typedef for NetDevice addition listeners container + typedef std::vector DeviceAdditionListenerList; + protected: /** @@ -266,22 +280,6 @@ class Node : public Object */ void Construct (void); - /** - * \brief Protocol handler entry. - * This structure is used to demultiplex all the protocols. - */ - struct ProtocolHandlerEntry { - 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; - /// Typedef for NetDevice addition listeners container - typedef std::vector DeviceAdditionListenerList; - uint32_t m_id; //!< Node id for this node uint32_t m_sid; //!< System id for this node std::vector > m_devices; //!< Devices associated to this node diff --git a/src/network/test/drop-tail-queue-test-suite.cc b/src/network/test/drop-tail-queue-test-suite.cc index 56eff386a58..1edb03b9840 100644 --- a/src/network/test/drop-tail-queue-test-suite.cc +++ b/src/network/test/drop-tail-queue-test-suite.cc @@ -47,34 +47,34 @@ DropTailQueueTestCase::DoRun (void) p4 = Create (); NS_TEST_EXPECT_MSG_EQ (queue->GetNPackets (), 0, "There should be no packets in there"); - queue->Enqueue (p1); + queue->Enqueue (Create (p1)); NS_TEST_EXPECT_MSG_EQ (queue->GetNPackets (), 1, "There should be one packet in there"); - queue->Enqueue (p2); + queue->Enqueue (Create (p2)); NS_TEST_EXPECT_MSG_EQ (queue->GetNPackets (), 2, "There should be two packets in there"); - queue->Enqueue (p3); + queue->Enqueue (Create (p3)); NS_TEST_EXPECT_MSG_EQ (queue->GetNPackets (), 3, "There should be three packets in there"); - queue->Enqueue (p4); // will be dropped + queue->Enqueue (Create (p4)); // will be dropped NS_TEST_EXPECT_MSG_EQ (queue->GetNPackets (), 3, "There should be still three packets in there"); - Ptr p; + Ptr item; - p = queue->Dequeue (); - NS_TEST_EXPECT_MSG_EQ ((p != 0), true, "I want to remove the first packet"); + item = queue->Dequeue (); + NS_TEST_EXPECT_MSG_EQ ((item != 0), true, "I want to remove the first packet"); NS_TEST_EXPECT_MSG_EQ (queue->GetNPackets (), 2, "There should be two packets in there"); - NS_TEST_EXPECT_MSG_EQ (p->GetUid (), p1->GetUid (), "was this the first packet ?"); + NS_TEST_EXPECT_MSG_EQ (item->GetPacket ()->GetUid (), p1->GetUid (), "was this the first packet ?"); - p = queue->Dequeue (); - NS_TEST_EXPECT_MSG_EQ ((p != 0), true, "I want to remove the second packet"); + item = queue->Dequeue (); + NS_TEST_EXPECT_MSG_EQ ((item != 0), true, "I want to remove the second packet"); NS_TEST_EXPECT_MSG_EQ (queue->GetNPackets (), 1, "There should be one packet in there"); - NS_TEST_EXPECT_MSG_EQ (p->GetUid (), p2->GetUid (), "Was this the second packet ?"); + NS_TEST_EXPECT_MSG_EQ (item->GetPacket ()->GetUid (), p2->GetUid (), "Was this the second packet ?"); - p = queue->Dequeue (); - NS_TEST_EXPECT_MSG_EQ ((p != 0), true, "I want to remove the third packet"); + item = queue->Dequeue (); + NS_TEST_EXPECT_MSG_EQ ((item != 0), true, "I want to remove the third packet"); NS_TEST_EXPECT_MSG_EQ (queue->GetNPackets (), 0, "There should be no packets in there"); - NS_TEST_EXPECT_MSG_EQ (p->GetUid (), p3->GetUid (), "Was this the third packet ?"); + NS_TEST_EXPECT_MSG_EQ (item->GetPacket ()->GetUid (), p3->GetUid (), "Was this the third packet ?"); - p = queue->Dequeue (); - NS_TEST_EXPECT_MSG_EQ ((p == 0), true, "There are really no packets in there"); + item = queue->Dequeue (); + NS_TEST_EXPECT_MSG_EQ ((item == 0), true, "There are really no packets in there"); } static class DropTailQueueTestSuite : public TestSuite diff --git a/src/network/test/red-queue-test-suite.cc b/src/network/test/red-queue-test-suite.cc index 17110721d4d..880d3eaae00 100644 --- a/src/network/test/red-queue-test-suite.cc +++ b/src/network/test/red-queue-test-suite.cc @@ -86,43 +86,43 @@ RedQueueTestCase::RunRedTest (StringValue mode) p8 = Create (pktSize); NS_TEST_EXPECT_MSG_EQ (queue->GetQueueSize (), 0 * modeSize, "There should be no packets in there"); - queue->Enqueue (p1); + queue->Enqueue (Create (p1)); NS_TEST_EXPECT_MSG_EQ (queue->GetQueueSize (), 1 * modeSize, "There should be one packet in there"); - queue->Enqueue (p2); + queue->Enqueue (Create (p2)); NS_TEST_EXPECT_MSG_EQ (queue->GetQueueSize (), 2 * modeSize, "There should be two packets in there"); - queue->Enqueue (p3); - queue->Enqueue (p4); - queue->Enqueue (p5); - queue->Enqueue (p6); - queue->Enqueue (p7); - queue->Enqueue (p8); + queue->Enqueue (Create (p3)); + queue->Enqueue (Create (p4)); + queue->Enqueue (Create (p5)); + queue->Enqueue (Create (p6)); + queue->Enqueue (Create (p7)); + queue->Enqueue (Create (p8)); NS_TEST_EXPECT_MSG_EQ (queue->GetQueueSize (), 8 * modeSize, "There should be eight packets in there"); - Ptr p; + Ptr item; - p = queue->Dequeue (); - NS_TEST_EXPECT_MSG_EQ ((p != 0), true, "I want to remove the first packet"); + item = queue->Dequeue (); + NS_TEST_EXPECT_MSG_EQ ((item != 0), true, "I want to remove the first packet"); NS_TEST_EXPECT_MSG_EQ (queue->GetQueueSize (), 7 * modeSize, "There should be seven packets in there"); - NS_TEST_EXPECT_MSG_EQ (p->GetUid (), p1->GetUid (), "was this the first packet ?"); + NS_TEST_EXPECT_MSG_EQ (item->GetPacket ()->GetUid (), p1->GetUid (), "was this the first packet ?"); - p = queue->Dequeue (); - NS_TEST_EXPECT_MSG_EQ ((p != 0), true, "I want to remove the second packet"); + item = queue->Dequeue (); + NS_TEST_EXPECT_MSG_EQ ((item != 0), true, "I want to remove the second packet"); NS_TEST_EXPECT_MSG_EQ (queue->GetQueueSize (), 6 * modeSize, "There should be six packet in there"); - NS_TEST_EXPECT_MSG_EQ (p->GetUid (), p2->GetUid (), "Was this the second packet ?"); + NS_TEST_EXPECT_MSG_EQ (item->GetPacket ()->GetUid (), p2->GetUid (), "Was this the second packet ?"); - p = queue->Dequeue (); - NS_TEST_EXPECT_MSG_EQ ((p != 0), true, "I want to remove the third packet"); + item = queue->Dequeue (); + NS_TEST_EXPECT_MSG_EQ ((item != 0), true, "I want to remove the third packet"); NS_TEST_EXPECT_MSG_EQ (queue->GetQueueSize (), 5 * modeSize, "There should be five packets in there"); - NS_TEST_EXPECT_MSG_EQ (p->GetUid (), p3->GetUid (), "Was this the third packet ?"); + NS_TEST_EXPECT_MSG_EQ (item->GetPacket ()->GetUid (), p3->GetUid (), "Was this the third packet ?"); - p = queue->Dequeue (); - p = queue->Dequeue (); - p = queue->Dequeue (); - p = queue->Dequeue (); - p = queue->Dequeue (); + item = queue->Dequeue (); + item = queue->Dequeue (); + item = queue->Dequeue (); + item = queue->Dequeue (); + item = queue->Dequeue (); - p = queue->Dequeue (); - NS_TEST_EXPECT_MSG_EQ ((p == 0), true, "There are really no packets in there"); + item = queue->Dequeue (); + NS_TEST_EXPECT_MSG_EQ ((item == 0), true, "There are really no packets in there"); // test 2: more data, but with no drops @@ -257,7 +257,7 @@ RedQueueTestCase::Enqueue (Ptr queue, uint32_t size, uint32_t nPkt) { for (uint32_t i = 0; i < nPkt; i++) { - queue->Enqueue (Create (size)); + queue->Enqueue (Create (Create (size))); } } diff --git a/src/network/utils/drop-tail-queue.cc b/src/network/utils/drop-tail-queue.cc index 9e68e73584a..ef5fc11b50a 100644 --- a/src/network/utils/drop-tail-queue.cc +++ b/src/network/utils/drop-tail-queue.cc @@ -83,9 +83,10 @@ DropTailQueue::GetMode (void) const } bool -DropTailQueue::DoEnqueue (Ptr p) +DropTailQueue::DoEnqueue (Ptr item) { - NS_LOG_FUNCTION (this << p); + NS_LOG_FUNCTION (this << item); + Ptr p = item->GetPacket (); if (m_mode == QUEUE_MODE_PACKETS && (m_packets.size () >= m_maxPackets)) { @@ -102,7 +103,7 @@ DropTailQueue::DoEnqueue (Ptr p) } m_bytesInQueue += p->GetSize (); - m_packets.push (p); + m_packets.push (item); NS_LOG_LOGIC ("Number packets " << m_packets.size ()); NS_LOG_LOGIC ("Number bytes " << m_bytesInQueue); @@ -110,7 +111,7 @@ DropTailQueue::DoEnqueue (Ptr p) return true; } -Ptr +Ptr DropTailQueue::DoDequeue (void) { NS_LOG_FUNCTION (this); @@ -121,19 +122,19 @@ DropTailQueue::DoDequeue (void) return 0; } - Ptr p = m_packets.front (); + Ptr item = m_packets.front (); m_packets.pop (); - m_bytesInQueue -= p->GetSize (); + m_bytesInQueue -= item->GetPacket ()->GetSize (); - NS_LOG_LOGIC ("Popped " << p); + NS_LOG_LOGIC ("Popped " << item); NS_LOG_LOGIC ("Number packets " << m_packets.size ()); NS_LOG_LOGIC ("Number bytes " << m_bytesInQueue); - return p; + return item; } -Ptr +Ptr DropTailQueue::DoPeek (void) const { NS_LOG_FUNCTION (this); @@ -144,12 +145,12 @@ DropTailQueue::DoPeek (void) const return 0; } - Ptr p = m_packets.front (); + Ptr item = m_packets.front (); NS_LOG_LOGIC ("Number packets " << m_packets.size ()); NS_LOG_LOGIC ("Number bytes " << m_bytesInQueue); - return p; + return item; } } // namespace ns3 diff --git a/src/network/utils/drop-tail-queue.h b/src/network/utils/drop-tail-queue.h index d5de0cefe2b..64457b307ad 100644 --- a/src/network/utils/drop-tail-queue.h +++ b/src/network/utils/drop-tail-queue.h @@ -64,11 +64,11 @@ class DropTailQueue : public Queue { DropTailQueue::QueueMode GetMode (void) const; private: - virtual bool DoEnqueue (Ptr p); - virtual Ptr DoDequeue (void); - virtual Ptr DoPeek (void) const; + virtual bool DoEnqueue (Ptr item); + virtual Ptr DoDequeue (void); + virtual Ptr DoPeek (void) const; - std::queue > m_packets; //!< the packets in the queue + std::queue > m_packets; //!< the items in the queue uint32_t m_maxPackets; //!< max packets in the queue uint32_t m_maxBytes; //!< max bytes in the queue uint32_t m_bytesInQueue; //!< actual bytes in the queue diff --git a/src/network/utils/queue.cc b/src/network/utils/queue.cc index 2f72b381385..99a16e128cc 100644 --- a/src/network/utils/queue.cc +++ b/src/network/utils/queue.cc @@ -24,6 +24,35 @@ namespace ns3 { NS_LOG_COMPONENT_DEFINE ("Queue"); +QueueItem::QueueItem (Ptr p) +{ + m_packet = p; +} + +QueueItem::~QueueItem() +{ + NS_LOG_FUNCTION (this); +} + +Ptr +QueueItem::GetPacket (void) const +{ + return m_packet; +} + +void +QueueItem::Print (std::ostream& os) const +{ + os << GetPacket(); +} + +std::ostream & operator << (std::ostream &os, const QueueItem &item) +{ + item.Print (os); + return os; +} + + NS_OBJECT_ENSURE_REGISTERED (Queue); TypeId @@ -63,20 +92,20 @@ Queue::~Queue() bool -Queue::Enqueue (Ptr p) +Queue::Enqueue (Ptr item) { - NS_LOG_FUNCTION (this << p); + NS_LOG_FUNCTION (this << item); // // If DoEnqueue fails, Queue::Drop is called by the subclass // - bool retval = DoEnqueue (p); + bool retval = DoEnqueue (item); if (retval) { NS_LOG_LOGIC ("m_traceEnqueue (p)"); - m_traceEnqueue (p); + m_traceEnqueue (item->GetPacket ()); - uint32_t size = p->GetSize (); + uint32_t size = item->GetPacket ()->GetSize (); m_nBytes += size; m_nTotalReceivedBytes += size; @@ -86,15 +115,16 @@ Queue::Enqueue (Ptr p) return retval; } -Ptr +Ptr Queue::Dequeue (void) { NS_LOG_FUNCTION (this); - Ptr packet = DoDequeue (); + Ptr item = DoDequeue (); - if (packet != 0) + if (item != 0) { + Ptr packet = item->GetPacket (); NS_ASSERT (m_nBytes >= packet->GetSize ()); NS_ASSERT (m_nPackets > 0); @@ -104,7 +134,7 @@ Queue::Dequeue (void) NS_LOG_LOGIC ("m_traceDequeue (packet)"); m_traceDequeue (packet); } - return packet; + return item; } void @@ -117,7 +147,7 @@ Queue::DequeueAll (void) } } -Ptr +Ptr Queue::Peek (void) const { NS_LOG_FUNCTION (this); diff --git a/src/network/utils/queue.h b/src/network/utils/queue.h index 7f7c8c638b4..a621aa5877c 100644 --- a/src/network/utils/queue.h +++ b/src/network/utils/queue.h @@ -36,6 +36,70 @@ namespace ns3 { * \ingroup network * \defgroup queue Queue */ + +/** + * \ingroup queue + * \brief Base class to represent items of packet Queues + * + * An item stored in an ns-3 packet Queue contains a packet and possibly other + * information. An item of the base class only contains a packet. Subclasses + * can be derived from this base class to allow items to contain additional + * information. + */ +class QueueItem : public SimpleRefCount +{ +public: + /** + * \brief Create a queue item containing a packet. + * \param p the packet included in the created item. + */ + QueueItem (Ptr p); + + virtual ~QueueItem (); + + /** + * \return the packet included in this item. + */ + Ptr GetPacket (void) const; + /** + * \brief Print the item contents. + * \param os output stream in which the data should be printed. + */ + virtual void Print (std::ostream &os) const; + +private: + /** + * \brief Default constructor + * + * Defined and unimplemented to avoid misuse + */ + QueueItem (); + /** + * \brief Copy constructor + * + * Defined and unimplemented to avoid misuse + */ + QueueItem (const QueueItem &); + /** + * \brief Assignment operator + * + * Defined and unimplemented to avoid misuse + * \returns + */ + QueueItem &operator = (const QueueItem &); + + Ptr m_packet; +}; + +/** + * \brief Stream insertion operator. + * + * \param os the stream + * \param item the item + * \returns a reference to the stream + */ +std::ostream& operator<< (std::ostream& os, const QueueItem &item); + /** * \ingroup queue * \brief Abstract base class for packet Queues @@ -59,21 +123,21 @@ class Queue : public Object */ bool IsEmpty (void) const; /** - * Place a packet into the rear of the Queue - * \param p packet to enqueue + * Place a queue item into the rear of the Queue + * \param item item to enqueue * \return True if the operation was successful; false otherwise */ - bool Enqueue (Ptr p); + bool Enqueue (Ptr item); /** - * Remove a packet from the front of the Queue - * \return 0 if the operation was not successful; the packet otherwise. + * Remove an item from the front of the Queue + * \return 0 if the operation was not successful; the item otherwise. */ - Ptr Dequeue (void); + Ptr Dequeue (void); /** * Get a copy of the item at the front of the queue without removing it - * \return 0 if the operation was not successful; the packet otherwise. + * \return 0 if the operation was not successful; the item otherwise. */ - Ptr Peek (void) const; + Ptr Peek (void) const; /** * Flush the queue. @@ -156,29 +220,29 @@ class Queue : public Object private: /** - * Push a packet in the queue - * \param p the packet to enqueue + * Push an item in the queue + * \param item the item to enqueue * \return true if success, false if the packet has been dropped. */ - virtual bool DoEnqueue (Ptr p) = 0; + virtual bool DoEnqueue (Ptr item) = 0; /** - * Pull a packet from the queue - * \return the packet. + * Pull an item from the queue + * \return the item. */ - virtual Ptr DoDequeue (void) = 0; + virtual Ptr DoDequeue (void) = 0; /** - * Peek the front packet in the queue - * \return the packet. + * Peek the front item in the queue + * \return the item. */ - virtual Ptr DoPeek (void) const = 0; + virtual Ptr DoPeek (void) const = 0; protected: /** - * \brief Drop a packet - * \param packet packet that was dropped + * \brief Drop a packet + * \param p packet that was dropped * This method is called by subclasses to notify parent (this class) of packet drops. */ - void Drop (Ptr packet); + void Drop (Ptr p); /// Traced callback: fired when a packet is enqueued TracedCallback > m_traceEnqueue; diff --git a/src/network/utils/red-queue.cc b/src/network/utils/red-queue.cc index db64088007b..734087d753e 100644 --- a/src/network/utils/red-queue.cc +++ b/src/network/utils/red-queue.cc @@ -209,9 +209,10 @@ RedQueue::AssignStreams (int64_t stream) } bool -RedQueue::DoEnqueue (Ptr p) +RedQueue::DoEnqueue (Ptr item) { - NS_LOG_FUNCTION (this << p); + NS_LOG_FUNCTION (this << item); + Ptr p = item->GetPacket (); if (!m_hasRedStarted ) { @@ -324,7 +325,7 @@ RedQueue::DoEnqueue (Ptr p) } m_bytesInQueue += p->GetSize (); - m_packets.push_back (p); + m_packets.push_back (item); NS_LOG_LOGIC ("Number packets " << m_packets.size ()); NS_LOG_LOGIC ("Number bytes " << m_bytesInQueue); @@ -609,7 +610,7 @@ RedQueue::GetQueueSize (void) } } -Ptr +Ptr RedQueue::DoDequeue (void) { NS_LOG_FUNCTION (this); @@ -625,20 +626,20 @@ RedQueue::DoDequeue (void) else { m_idle = 0; - Ptr p = m_packets.front (); + Ptr item = m_packets.front (); m_packets.pop_front (); - m_bytesInQueue -= p->GetSize (); + m_bytesInQueue -= item->GetPacket ()->GetSize (); - NS_LOG_LOGIC ("Popped " << p); + NS_LOG_LOGIC ("Popped " << item); NS_LOG_LOGIC ("Number packets " << m_packets.size ()); NS_LOG_LOGIC ("Number bytes " << m_bytesInQueue); - return p; + return item; } } -Ptr +Ptr RedQueue::DoPeek (void) const { NS_LOG_FUNCTION (this); @@ -648,12 +649,12 @@ RedQueue::DoPeek (void) const return 0; } - Ptr p = m_packets.front (); + Ptr item = m_packets.front (); NS_LOG_LOGIC ("Number packets " << m_packets.size ()); NS_LOG_LOGIC ("Number bytes " << m_bytesInQueue); - return p; + return item; } } // namespace ns3 diff --git a/src/network/utils/red-queue.h b/src/network/utils/red-queue.h index 4e0e9232858..15a14307d82 100644 --- a/src/network/utils/red-queue.h +++ b/src/network/utils/red-queue.h @@ -177,9 +177,9 @@ class RedQueue : public Queue int64_t AssignStreams (int64_t stream); private: - virtual bool DoEnqueue (Ptr p); - virtual Ptr DoDequeue (void); - virtual Ptr DoPeek (void) const; + virtual bool DoEnqueue (Ptr item); + virtual Ptr DoDequeue (void); + virtual Ptr DoPeek (void) const; /** * \brief Initialize the queue parameters. @@ -233,7 +233,7 @@ class RedQueue : public Queue double ModifyP (double p, uint32_t count, uint32_t countBytes, uint32_t meanPktSize, bool wait, uint32_t size); - std::list > m_packets; //!< packets in the queue + std::list > m_packets; //!< packets in the queue uint32_t m_bytesInQueue; //!< bytes in the queue bool m_hasRedStarted; //!< True if RED has started diff --git a/src/network/utils/simple-net-device.cc b/src/network/utils/simple-net-device.cc index 3633e5accdd..e227efda867 100644 --- a/src/network/utils/simple-net-device.cc +++ b/src/network/utils/simple-net-device.cc @@ -444,11 +444,11 @@ SimpleNetDevice::SendFrom (Ptr p, const Address& source, const Address& p->AddPacketTag (tag); - if (m_queue->Enqueue (p)) + if (m_queue->Enqueue (Create (p))) { if (m_queue->GetNPackets () == 1 && !TransmitCompleteEvent.IsRunning ()) { - p = m_queue->Dequeue (); + p = m_queue->Dequeue ()->GetPacket (); p->RemovePacketTag (tag); Time txTime = Time (0); if (m_bps > DataRate (0)) @@ -477,7 +477,7 @@ SimpleNetDevice::TransmitComplete () return; } - Ptr packet = m_queue->Dequeue (); + Ptr packet = m_queue->Dequeue ()->GetPacket (); SimpleTag tag; packet->RemovePacketTag (tag); diff --git a/src/point-to-point/model/point-to-point-net-device.cc b/src/point-to-point/model/point-to-point-net-device.cc index b941bdf7ea7..c77f285347f 100644 --- a/src/point-to-point/model/point-to-point-net-device.cc +++ b/src/point-to-point/model/point-to-point-net-device.cc @@ -280,18 +280,27 @@ PointToPointNetDevice::TransmitComplete (void) m_phyTxEndTrace (m_currentPkt); m_currentPkt = 0; - Ptr p = m_queue->Dequeue (); - if (p == 0) + Ptr txq = GetTxQueue (0); + + Ptr item = m_queue->Dequeue (); + if (item == 0) { - // - // No packet was on the queue, so we just exit. - // + NS_LOG_LOGIC ("No pending packets in device queue after tx complete"); + txq->Wake (); return; } // - // Got another packet off of the queue, so start the transmit process agin. + // Got another packet off of the queue, so start the transmit process again. + // If the queue was stopped, start it again. Note that we cannot wake the upper + // layers because otherwise a packet is sent to the device while the machine + // state is busy, thus causing the assert in TransmitStart to fail. // + if (txq->IsStopped ()) + { + txq->Start (); + } + Ptr p = item->GetPacket (); m_snifferTrace (p); m_promiscSnifferTrace (p); TransmitStart (p); @@ -510,6 +519,12 @@ PointToPointNetDevice::Send ( const Address &dest, uint16_t protocolNumber) { + Ptr txq = GetTxQueue (0); + if (txq->IsStopped ()) + { + NS_LOG_WARN ("Send should not be called when the device is stopped"); + } + NS_LOG_FUNCTION (this << packet << dest << protocolNumber); NS_LOG_LOGIC ("p=" << packet << ", dest=" << &dest); NS_LOG_LOGIC ("UID is " << packet->GetUid ()); @@ -535,14 +550,14 @@ PointToPointNetDevice::Send ( // // We should enqueue and dequeue the packet to hit the tracing hooks. // - if (m_queue->Enqueue (packet)) + if (m_queue->Enqueue (Create (packet))) { // // If the channel is ready for transition we send the packet right now // if (m_txMachineState == READY) { - packet = m_queue->Dequeue (); + packet = m_queue->Dequeue ()->GetPacket (); m_snifferTrace (packet); m_promiscSnifferTrace (packet); return TransmitStart (packet); @@ -552,6 +567,7 @@ PointToPointNetDevice::Send ( // Enqueue may fail (overflow) m_macTxDropTrace (packet); + txq->Stop (); return false; } diff --git a/src/sixlowpan/test/sixlowpan-fragmentation-test.cc b/src/sixlowpan/test/sixlowpan-fragmentation-test.cc index c2d7a4f0ce3..39c10db72f0 100644 --- a/src/sixlowpan/test/sixlowpan-fragmentation-test.cc +++ b/src/sixlowpan/test/sixlowpan-fragmentation-test.cc @@ -44,6 +44,7 @@ #include "ns3/ipv6-l3-protocol.h" #include "ns3/icmpv6-l4-protocol.h" +#include "ns3/traffic-control-layer.h" #include #include @@ -77,6 +78,10 @@ AddInternetStack (Ptr node) //UDP Ptr udp = CreateObject (); node->AggregateObject (udp); + + // Traffic Control + Ptr tc = CreateObject (); + node->AggregateObject (tc); } diff --git a/src/sixlowpan/test/sixlowpan-hc1-test.cc b/src/sixlowpan/test/sixlowpan-hc1-test.cc index 9cff7ba2bb4..92f0fdf44d4 100644 --- a/src/sixlowpan/test/sixlowpan-hc1-test.cc +++ b/src/sixlowpan/test/sixlowpan-hc1-test.cc @@ -37,6 +37,7 @@ #include "ns3/udp-l4-protocol.h" #include "ns3/ipv6-list-routing.h" #include "ns3/ipv6-static-routing.h" +#include "ns3/traffic-control-layer.h" #include "ns3/sixlowpan-net-device.h" @@ -65,6 +66,9 @@ AddInternetStack6 (Ptr node) //UDP Ptr udp = CreateObject (); node->AggregateObject (udp); + // Traffic Control + Ptr tc = CreateObject (); + node->AggregateObject (tc); } diff --git a/src/sixlowpan/test/sixlowpan-iphc-test.cc b/src/sixlowpan/test/sixlowpan-iphc-test.cc index 40e975b25e5..8fe4f9c3e44 100644 --- a/src/sixlowpan/test/sixlowpan-iphc-test.cc +++ b/src/sixlowpan/test/sixlowpan-iphc-test.cc @@ -37,6 +37,7 @@ #include "ns3/udp-l4-protocol.h" #include "ns3/ipv6-list-routing.h" #include "ns3/ipv6-static-routing.h" +#include "ns3/traffic-control-layer.h" #include "ns3/sixlowpan-net-device.h" @@ -65,6 +66,9 @@ AddInternetStack6 (Ptr node) //UDP Ptr udp = CreateObject (); node->AggregateObject (udp); + // Traffic Control + Ptr tc = CreateObject (); + node->AggregateObject (tc); } diff --git a/src/spectrum/model/aloha-noack-net-device.cc b/src/spectrum/model/aloha-noack-net-device.cc index 68fb30a0f3e..dba6eb76692 100644 --- a/src/spectrum/model/aloha-noack-net-device.cc +++ b/src/spectrum/model/aloha-noack-net-device.cc @@ -378,7 +378,7 @@ AlohaNoackNetDevice::SendFrom (Ptr packet, const Address& src, const Add else { NS_LOG_LOGIC ("enqueueing new packet"); - if (m_queue->Enqueue (packet) == false) + if (m_queue->Enqueue (Create (packet)) == false) { m_macTxDropTrace (packet); sendOk = false; @@ -389,7 +389,7 @@ AlohaNoackNetDevice::SendFrom (Ptr packet, const Address& src, const Add { NS_LOG_LOGIC ("deferring TX, enqueueing new packet"); NS_ASSERT (m_queue); - if (m_queue->Enqueue (packet) == false) + if (m_queue->Enqueue (Create (packet)) == false) { m_macTxDropTrace (packet); sendOk = false; @@ -434,8 +434,9 @@ AlohaNoackNetDevice::NotifyTransmissionEnd (Ptr) NS_ASSERT (m_queue); if (m_queue->IsEmpty () == false) { - m_currentPkt = m_queue->Dequeue (); - NS_ASSERT (m_currentPkt); + Ptr item = m_queue->Dequeue (); + NS_ASSERT (item); + m_currentPkt = item->GetPacket (); NS_LOG_LOGIC ("scheduling transmission now"); Simulator::ScheduleNow (&AlohaNoackNetDevice::StartTransmission, this); } diff --git a/src/test/ns3tcp/ns3tcp-loss-test-suite.cc b/src/test/ns3tcp/ns3tcp-loss-test-suite.cc index 3525b57555c..71617934234 100644 --- a/src/test/ns3tcp/ns3tcp-loss-test-suite.cc +++ b/src/test/ns3tcp/ns3tcp-loss-test-suite.cc @@ -78,7 +78,7 @@ class Ns3TcpLossTestCase : public TestCase bool m_needToClose; std::string m_tcpModel; - void Ipv4L3Tx (std::string context, Ptr packet, Ptr ipv4, uint32_t interface); + void Ipv4L3Tx (std::string context, const Ipv4Header & ipv4Header, Ptr packet, Ptr ipv4, uint32_t interface); void CwndTracer (uint32_t oldval, uint32_t newval); void WriteUntilBufferFull (Ptr localSocket, uint32_t txSpace); void StartFlow (Ptr localSocket, @@ -145,18 +145,10 @@ Ns3TcpLossTestCase::DoTeardown (void) } void -Ns3TcpLossTestCase::Ipv4L3Tx (std::string context, Ptr packet, Ptr ipv4, uint32_t interface) +Ns3TcpLossTestCase::Ipv4L3Tx (std::string context, const Ipv4Header & ipv4Header, Ptr packet, Ptr ipv4, uint32_t interface) { // - // We're not testing IP so remove and toss the header. In order to do this, - // though, we need to copy the packet since we have a const version. - // - Ptr p = packet->Copy (); - Ipv4Header ipHeader; - p->RemoveHeader (ipHeader); - - // - // What is left is the TCP header and any data that may be sent. We aren't + // packet includes the TCP header and any data that may be sent. We aren't // sending any TCP data, so we expect what remains is only TCP header, which // is a small thing to save. // @@ -171,7 +163,7 @@ Ns3TcpLossTestCase::Ipv4L3Tx (std::string context, Ptr packet, Ptr m_pcapFile.Write (uint32_t (tMicroSeconds / 1000000), uint32_t (tMicroSeconds % 1000000), - p + packet ); } else @@ -187,7 +179,7 @@ Ns3TcpLossTestCase::Ipv4L3Tx (std::string context, Ptr packet, Ptr NS_LOG_DEBUG ("read " << readLen); uint8_t *actual = new uint8_t[readLen]; - p->CopyData (actual, readLen); + packet->CopyData (actual, readLen); int result = memcmp (actual, expected, readLen); diff --git a/src/test/ns3tcp/ns3tcp-state-test-suite.cc b/src/test/ns3tcp/ns3tcp-state-test-suite.cc index b0c83ff25dd..3f5f511452f 100644 --- a/src/test/ns3tcp/ns3tcp-state-test-suite.cc +++ b/src/test/ns3tcp/ns3tcp-state-test-suite.cc @@ -78,7 +78,7 @@ class Ns3TcpStateTestCase : public TestCase bool m_writeLogging; bool m_needToClose; - void Ipv4L3Tx (std::string context, Ptr packet, Ptr ipv4, uint32_t interface); + void Ipv4L3Tx (std::string context, const Ipv4Header & ipv4Header, Ptr packet, Ptr ipv4, uint32_t interface); void WriteUntilBufferFull (Ptr localSocket, uint32_t txSpace); void StartFlow (Ptr localSocket, Ipv4Address servAddress, @@ -143,20 +143,12 @@ Ns3TcpStateTestCase::DoTeardown (void) } void -Ns3TcpStateTestCase::Ipv4L3Tx (std::string context, Ptr packet, Ptr ipv4, uint32_t interface) +Ns3TcpStateTestCase::Ipv4L3Tx (std::string context, const Ipv4Header & ipv4Header, Ptr packet, Ptr ipv4, uint32_t interface) { - // - // We're not testing IP so remove and toss the header. In order to do this, - // though, we need to copy the packet since we have a const version. - // - Ptr p = packet->Copy (); - Ipv4Header ipHeader; - p->RemoveHeader (ipHeader); - if (g_log.IsEnabled (ns3::LOG_DEBUG)) { TcpHeader th; - p->PeekHeader (th); + packet->PeekHeader (th); std::clog << Simulator::Now ().GetSeconds () << " TCP header " << th << std::endl; } @@ -175,7 +167,7 @@ Ns3TcpStateTestCase::Ipv4L3Tx (std::string context, Ptr packet, Pt m_pcapFile.Write (uint32_t (tMicroSeconds / 1000000), uint32_t (tMicroSeconds % 1000000), - p); + packet); } else { @@ -188,7 +180,7 @@ Ns3TcpStateTestCase::Ipv4L3Tx (std::string context, Ptr packet, Pt m_pcapFile.Read (expected, sizeof(expected), tsSec, tsUsec, inclLen, origLen, readLen); uint8_t *actual = new uint8_t[readLen]; - p->CopyData (actual, readLen); + packet->CopyData (actual, readLen); uint32_t result = memcmp (actual, expected, readLen); diff --git a/src/test/traced/traced-callback-typedef-test-suite.cc b/src/test/traced/traced-callback-typedef-test-suite.cc index ab1a7040a66..a94b4af2e7d 100644 --- a/src/test/traced/traced-callback-typedef-test-suite.cc +++ b/src/test/traced/traced-callback-typedef-test-suite.cc @@ -411,8 +411,8 @@ TracedCallbackTypedefTestCase::DoRun (void) empty, empty); CHECK (Ipv4L3Protocol::TxRxTracedCallback, - Ptr, Ptr, uint32_t, - empty, empty); + const Ipv4Header &, Ptr, Ptr, + uint32_t, empty); CHECK (Ipv6L3Protocol::DropTracedCallback, const Ipv6Header &, Ptr, @@ -424,8 +424,8 @@ TracedCallbackTypedefTestCase::DoRun (void) empty, empty); CHECK (Ipv6L3Protocol::TxRxTracedCallback, - Ptr, Ptr, uint32_t, - empty, empty); + const Ipv6Header &, Ptr, Ptr, + uint32_t, empty); CHECK (LrWpanMac::SentTracedCallback, Ptr, uint8_t, uint8_t, diff --git a/src/traffic-control/doc/child-queue-discs.dia b/src/traffic-control/doc/child-queue-discs.dia new file mode 100644 index 00000000000..b9cff745e85 Binary files /dev/null and b/src/traffic-control/doc/child-queue-discs.dia differ diff --git a/src/traffic-control/doc/root-queue-disc.dia b/src/traffic-control/doc/root-queue-disc.dia new file mode 100644 index 00000000000..492409283c0 Binary files /dev/null and b/src/traffic-control/doc/root-queue-disc.dia differ diff --git a/src/traffic-control/doc/traffic-control.rst b/src/traffic-control/doc/traffic-control.rst new file mode 100644 index 00000000000..bc00eff7e68 --- /dev/null +++ b/src/traffic-control/doc/traffic-control.rst @@ -0,0 +1,204 @@ +Traffic Control +--------------- + +.. heading hierarchy: + ------------- Chapter + ************* Section (#.#) + ============= Subsection (#.#.#) + ############# Paragraph (no number) + +This layer has been designed to be between NetDevices (L2) and any network +protocol (e.g. IP). It is responsible to analyze packets and to perform actions +on them: the most common is scheduling, but many others are planned / implemented. + +Brief description of the 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}. + +Introducing Traffic Control Layer +********************************* + +The layer is responsible to take actions to schedule or filter the traffic for +both INPUT and OUTPUT directions (called also RX and TX). To interact +with the IP layer and the NetDevice layer, we edited in the following manner +the IPv{4,6}Interface and IPv{4,6}L3Protocol. + +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 + +Queue disciplines +-------------------------------------------------------------- +Packets received by the Traffic Control layer for transmission to a netdevice +can be passed to a Queue Discipline to perform scheduling and policing. +A netdevice can have a single (root) queue disc aggregated to it. +Aggregating a queue disc to a netdevice is not mandatory. If a netdevice does +not have a queue disc aggregated to it, the traffic control layer sends the packets +directly to the netdevice. This is the case, for instance, of the loopback netdevice. + +The traffic control layer interacts with a queue disc in a simple manner: after requesting +to enqueue a packet, the traffic control layer requests the qdisc to "run", i.e., to +dequeue a set of packets, until a predefined number ("quota") of packets is dequeued +or the netdevice stops the queue disc. + +Multi-queue devices (such as Wifi) are explicitly taken into account. Each +netdevice has a vector of as many NetDeviceQueue objects as the number of +transmission queues.A NetDeviceQueue object stores information related to a +single transmission queue, such as the status (i.e., whether the queue has been +stopped or not) and (yet to come) data used by techniques such as Byte Queue Limits. +Additionally, the NetDeviceQueue class offers public methods to enquire about the +status of a transmission queue and to start, stop or wake a transmission queue. +To wake a transmission queue means requesting the associated queue disc (see +below for details) to run. + +"Classic" queue discs (such as pfifo_fast, red, codel and many others) are not aware +of the number of transmission queues used by the netdevice. More recently, +multi-queue aware queue discs (such mq and mq-prio) have been mainlined into the +Linux kernel. Multi-queue aware queue discs create as many queues internally as +the number of transmission queues used by the netdevice. Additionally, they +enqueue packets into their internal queues based on a packet field (implemented +as an |ns3| tag) that can be set by calling a netdevice function. Therefore, +each packet is enqueued in the "same" queue both inside the queue disc and inside +the netdevice. Classic queue discs (such as fq-codel) are classful, i.e., they +manage internal queues whose packets are scheduled by means of other kinds of +queue discs. However, there is no close relationship between the internal queues +of the queue disc and the transmission queues of the netdevice. + +When a root queue disc, be it a classic classful one or a multi-queue aware one, +receives a packet to enqueue, it selects an internal queue disc and requests it +to enqueue a packet. When a root queue disc is requested to dequeue a packet, it +selects an internal queue disc and requests it to dequeue a packet. A multi-queue +aware queue disc is requested to select an internal queue disc whose corresponding +device transmission queue is not stopped. + +There are a couple of operations that need to be performed when setting up a queue +disc, which vary depending on whether we are setting up a root queue disc or a +child queue disc. + +Setting up a root queue disc +***************************** + +.. _fig-root-queue-disc: + +.. figure:: figures/root-queue-disc.* + + Setup of a root queue disc + + +:ref:`fig-root-queue-disc` shows how to configure a root queue disc. Basically: + +* A root queue disc needs to be aggregated to a netdevice object +* The m_devQueue member of the root queue disc must point to one of the device transmission queues (e.g., the first one) +* A wake callback must be set on all the device transmissio queues to point to the Run method of the root queue disc + +Setting up child queue discs +******************************* + +.. _fig-child-queue-discs: + +.. figure:: figures/child-queue-discs.* + + Setup of child queue discs + + +:ref:`fig-child-queue-discs` shows how to configure queue discs that are children +of a multi-queue aware (root) queue disc. Basically: + +* Each child queue disc needs to be aggregated to a NetDeviceQueue object +* The m_devQueue member of a child queue disc must point to the corresponding device transmission queue +* A wake callback must be set on each device transmissio queue to point to the Run method of the corresponding child queue disc + +In case of queue discs that are children of a classic classful (root) queue disc, +none of the above operations need to be performed, as there is not a match between +the child queue discs and the device transmission queues. diff --git a/src/traffic-control/examples/wscript b/src/traffic-control/examples/wscript new file mode 100644 index 00000000000..6c879c3b897 --- /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/helper/queue-disc-container.cc b/src/traffic-control/helper/queue-disc-container.cc new file mode 100644 index 00000000000..ecdd3a82fdd --- /dev/null +++ b/src/traffic-control/helper/queue-disc-container.cc @@ -0,0 +1,71 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2015 Universita' degli Studi di Napoli Federico II + * + * 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 "queue-disc-container.h" + +namespace ns3 { + +QueueDiscContainer::QueueDiscContainer () +{ +} + +QueueDiscContainer::QueueDiscContainer (Ptr qDisc) +{ + m_queueDiscs.push_back (qDisc); +} + +QueueDiscContainer::Iterator +QueueDiscContainer::Begin (void) const +{ + return m_queueDiscs.begin (); +} + +QueueDiscContainer::Iterator +QueueDiscContainer::End (void) const +{ + return m_queueDiscs.end (); +} + +uint32_t +QueueDiscContainer::GetN (void) const +{ + return m_queueDiscs.size (); +} + +Ptr +QueueDiscContainer::Get (uint32_t i) const +{ + return m_queueDiscs[i]; +} + +void +QueueDiscContainer::Add (QueueDiscContainer other) +{ + for (Iterator i = other.Begin (); i != other.End (); i++) + { + m_queueDiscs.push_back (*i); + } +} + +void +QueueDiscContainer::Add (Ptr qDisc) +{ + m_queueDiscs.push_back (qDisc); +} + +} // namespace ns3 diff --git a/src/traffic-control/helper/queue-disc-container.h b/src/traffic-control/helper/queue-disc-container.h new file mode 100644 index 00000000000..a34f5af009c --- /dev/null +++ b/src/traffic-control/helper/queue-disc-container.h @@ -0,0 +1,166 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2015 Universita' degli Studi di Napoli Federico II + * + * 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 QUEUE_DISC_CONTAINER_H +#define QUEUE_DISC_CONTAINER_H + +#include +#include +#include "ns3/queue-disc.h" + +namespace ns3 { + +/** + * \brief holds a vector of ns3::QueueDisc pointers + * + * Typically ns-3 QueueDiscs are installed on net devices using a traffic control + * helper. The helper Install method takes a NetDeviceContainer which holds + * some number of Ptr. For each of the net devices in the + * NetDeviceContainer the helper will instantiate a queue disc and install + * it to the net device. For each of the queue discs, the helper also + * adds the queue disc into a Container for later use by the caller. + * This is that container used to hold the Ptr which are + * instantiated by the traffic control helper. + */ +class QueueDiscContainer +{ +public: + /// QueueDisc container iterator + typedef std::vector >::const_iterator Iterator; + + /** + * Create an empty QueueDiscContainer. + */ + QueueDiscContainer (); + + /** + * \param qDisc a queue disc to add to the container + * + * Create a QueueDiscContainer with exactly one queue disc that has previously + * been instantiated + */ + QueueDiscContainer (Ptr qDisc); + + /** + * \brief Get an iterator which refers to the first QueueDisc in the + * container. + * + * QueueDiscs can be retrieved from the container in two ways. First, + * directly by an index into the container, and second, using an iterator. + * This method is used in the iterator method and is typically used in a + * for-loop to run through the QueueDiscs + * + * \code + * QueueDiscContainer::Iterator i; + * for (i = container.Begin (); i != container.End (); ++i) + * { + * (*i)->method (); // some QueueDisc method + * } + * \endcode + * + * \returns an iterator which refers to the first QueueDisc in the container. + */ + Iterator Begin (void) const; + + /** + * \brief Get an iterator which indicates past-the-last QueueDisc in the + * container. + * + * QueueDiscs can be retrieved from the container in two ways. First, + * directly by an index into the container, and second, using an iterator. + * This method is used in the iterator method and is typically used in a + * for-loop to run through the QueueDiscs + * + * \code + * QueueDiscContainer::Iterator i; + * for (i = container.Begin (); i != container.End (); ++i) + * { + * (*i)->method (); // some QueueDisc method + * } + * \endcode + * + * \returns an iterator which indicates an ending condition for a loop. + */ + Iterator End (void) const; + + /** + * \brief Get the number of Ptr stored in this container. + * + * QueueDiscs can be retrieved from the container in two ways. First, + * directly by an index into the container, and second, using an iterator. + * This method is used in the direct method and is typically used to + * define an ending condition in a for-loop that runs through the stored + * QueueDiscs + * + * \code + * uint32_t nQueueDiscs = container.GetN (); + * for (uint32_t i = 0 i < nQueueDiscs; ++i) + * { + * Ptr p = container.Get (i) + * i->method (); // some QueueDisc method + * } + * \endcode + * + * \returns the number of Ptr stored in this container. + */ + uint32_t GetN (void) const; + + /** + * \brief Get the Ptr stored in this container at a given + * index. + * + * QueueDiscs can be retrieved from the container in two ways. First, + * directly by an index into the container, and second, using an iterator. + * This method is used in the direct method and is used to retrieve the + * indexed Ptr. + * + * \code + * uint32_t nQueueDiscs = container.GetN (); + * for (uint32_t i = 0 i < nQueueDiscs; ++i) + * { + * Ptr p = container.Get (i) + * i->method (); // some QueueDisc method + * } + * \endcode + * + * \param i the index of the requested queue disc pointer. + * \returns the requested queue disc pointer. + */ + Ptr Get (uint32_t i) const; + + /** + * \brief Append the contents of another QueueDiscContainer to the end of + * this container. + * + * \param other The QueueDiscContainer to append. + */ + void Add (QueueDiscContainer other); + + /** + * \brief Append a single Ptr to this container. + * + * \param qDisc The Ptr to append. + */ + void Add (Ptr qDisc); + +private: + std::vector > m_queueDiscs; //!< QueueDiscs smart pointers +}; + +} // namespace ns3 + +#endif /* QUEUE_DISC_CONTAINER_H */ diff --git a/src/traffic-control/helper/queue-disc-helper.cc b/src/traffic-control/helper/queue-disc-helper.cc new file mode 100644 index 00000000000..fdcc02649c0 --- /dev/null +++ b/src/traffic-control/helper/queue-disc-helper.cc @@ -0,0 +1,87 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2015 Universita' degli Studi di Napoli Federico II + * + * 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 "ns3/log.h" +#include "ns3/traffic-control-layer.h" +#include "queue-disc-helper.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("QueueDiscHelper"); + +QueueDiscHelper::QueueDiscHelper () +{ + m_queueDiscFactory.SetTypeId ("ns3::PfifoFastQueueDisc"); +} + +void +QueueDiscHelper::SetQueueDiscType (std::string type) +{ + m_queueDiscFactory.SetTypeId (type); +} + +void +QueueDiscHelper::SetAttribute (std::string name, const AttributeValue& value) +{ + m_queueDiscFactory.Set (name, value); +} + +QueueDiscContainer +QueueDiscHelper::Install (Ptr d) +{ + QueueDiscContainer container; + + // A TrafficControlLayer object is aggregated by the InternetStackHelper, but check + // anyway because a queue disc has no effect without a TrafficControlLayer object + NS_ASSERT (d->GetNode ()->GetObject ()); + + // Check if a queue disc is already installed on this netdevice + Ptr q = d->GetObject (); + + if (q != 0) + { + NS_FATAL_ERROR ("QueueDiscHelper::Install (): Installing a queue disc " + "on a device already having an associated queue disc"); + return container; + } + + q = m_queueDiscFactory.Create (); + // This is a root queue disc, so it points to the first transmission queue of the + // netdevice and is aggregated to the netdevice object + q->SetNetDeviceQueue (d->GetTxQueue (0)); + q->SetWakeCbOnAllTxQueues (); + d->AggregateObject (q); + container.Add (q); + + return container; +} + +QueueDiscContainer +QueueDiscHelper::Install (NetDeviceContainer c) +{ + QueueDiscContainer container; + + for (NetDeviceContainer::Iterator i = c.Begin (); i != c.End (); ++i) + { + container.Add (Install (*i)); + } + + return container; +} + +} // namespace ns3 diff --git a/src/traffic-control/helper/queue-disc-helper.h b/src/traffic-control/helper/queue-disc-helper.h new file mode 100644 index 00000000000..89fc8da6b22 --- /dev/null +++ b/src/traffic-control/helper/queue-disc-helper.h @@ -0,0 +1,91 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2015 Universita' degli Studi di Napoli Federico II + * + * 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 QUEUE_DISC_HELPER_H +#define QUEUE_DISC_HELPER_H + +#include + +#include "ns3/object-factory.h" +#include "ns3/net-device-container.h" +#include "ns3/queue-disc-container.h" + +namespace ns3 { + +/** + * \brief Build a set of QueueDisc objects + * + * This class can help to create QueueDisc objects and map them to + * the corresponding devices. This map is stored at the Traffic Control + * layer. + */ +class QueueDiscHelper +{ +public: + /** + * Create a QueueDiscHelper to make life easier when creating QueueDisc + * objects. + */ + QueueDiscHelper (); + virtual ~QueueDiscHelper () {} + + /** + * Helper function used to set the type of queue disc to be created. + * + * \param type the type of queue + */ + void SetQueueDiscType (std::string type); + + /** + * Helper function used to set the queue disc attributes. + * + * \param name the name of the attribute to set on the queue disc + * \param value the value of the attribute to set on the queue disc + */ + void SetAttribute (std::string name, const AttributeValue &va1ue); + + /** + * \param c set of devices + * \returns a QueueDisc container with the queue discs installed on the devices + * + * This method creates a QueueDisc object of the type and with the + * attributes configured by QueueDiscHelper::SetQueueDisc for + * each device in the container. Then, stores the mapping between a + * device and the associated queue disc into the traffic control layer + * of the corresponding node. + */ + QueueDiscContainer Install (NetDeviceContainer c); + + /** + * \param d device + * \returns a QueueDisc container with the queue disc installed on the device + * + * This method creates a QueueDisc object of the type and with the + * attributes configured by QueueDiscHelper::SetQueueDisc for + * the given device. Then, stores the mapping between the device + * and the associated queue disc into the traffic control layer + * of the corresponding node. + */ + QueueDiscContainer Install (Ptr d); + +private: + ObjectFactory m_queueDiscFactory; //!< QueueDisc Factory +}; + +} // namespace ns3 + +#endif /* QUEUE_DISC_HELPER_H */ diff --git a/src/traffic-control/model/pfifo-fast-queue-disc.cc b/src/traffic-control/model/pfifo-fast-queue-disc.cc new file mode 100644 index 00000000000..8bfd4ebfd96 --- /dev/null +++ b/src/traffic-control/model/pfifo-fast-queue-disc.cc @@ -0,0 +1,310 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007, 2014 University of Washington + * + * 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 "ns3/log.h" +#include "ns3/enum.h" +#include "ns3/uinteger.h" +#include "ns3/pointer.h" +#include "ns3/string.h" +#include "ns3/ipv4-header.h" +#include "ns3/drop-tail-queue.h" +#include "pfifo-fast-queue-disc.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("PfifoFastQueueDisc"); + +NS_OBJECT_ENSURE_REGISTERED (PfifoFastQueueDisc); + +TypeId PfifoFastQueueDisc::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::PfifoFastQueueDisc") + .SetParent () + .AddConstructor () + .AddAttribute ("Mode", + "Whether to interpret the TOS byte as legacy TOS or DSCP", + EnumValue (QUEUE_MODE_DSCP), + MakeEnumAccessor (&PfifoFastQueueDisc::m_trafficClassMode), + MakeEnumChecker (QUEUE_MODE_TOS, "TOS semantics", + QUEUE_MODE_DSCP, "DSCP semantics")) + .AddAttribute ("Band0", + "A queue to use as the band 0.", + StringValue ("ns3::DropTailQueue"), + MakePointerAccessor (&PfifoFastQueueDisc::m_band0), + MakePointerChecker ()) + .AddAttribute ("Band1", + "A queue to use as the band 1.", + StringValue ("ns3::DropTailQueue"), + MakePointerAccessor (&PfifoFastQueueDisc::m_band1), + MakePointerChecker ()) + .AddAttribute ("Band2", + "A queue to use as the band 2.", + StringValue ("ns3::DropTailQueue"), + MakePointerAccessor (&PfifoFastQueueDisc::m_band2), + MakePointerChecker ()) + ; + + return tid; +} + +PfifoFastQueueDisc::PfifoFastQueueDisc () +{ + NS_LOG_FUNCTION (this); +} + +PfifoFastQueueDisc::~PfifoFastQueueDisc () +{ + NS_LOG_FUNCTION (this); +} + +bool +PfifoFastQueueDisc::DoEnqueue (Ptr item) +{ + NS_LOG_FUNCTION (this << item); + + uint32_t band = Classify (item); + + if (band == 0) + { + if (!m_band0->Enqueue (item)) + { + NS_LOG_LOGIC ("Enqueue failed -- dropping pkt"); + Drop (item->GetPacket ()); + return false; + } + NS_LOG_LOGIC ("Number packets band 0: " << m_band0->GetNPackets ()); + } + else if (band == 1) + { + if (!m_band1->Enqueue (item)) + { + NS_LOG_LOGIC ("Enqueue failed -- dropping pkt"); + Drop (item->GetPacket ()); + return false; + } + NS_LOG_LOGIC ("Number packets band 1: " << m_band1->GetNPackets ()); + } + else + { + if (!m_band2->Enqueue (item)) + { + NS_LOG_LOGIC ("Enqueue failed -- dropping pkt"); + Drop (item->GetPacket ()); + return false; + } + NS_LOG_LOGIC ("Number packets band 2: " << m_band2->GetNPackets ()); + } + return true; +} + +Ptr +PfifoFastQueueDisc::DoDequeue (void) +{ + NS_LOG_FUNCTION (this); + + Ptr item; + if ((item = DynamicCast (m_band0->Dequeue ())) != 0) + { + NS_LOG_LOGIC ("Popped from band 0: " << item); + NS_LOG_LOGIC ("Number packets band 0: " << m_band0->GetNPackets ()); + } + else if ((item = DynamicCast (m_band1->Dequeue ())) != 0) + { + NS_LOG_LOGIC ("Popped from band 1: " << item); + NS_LOG_LOGIC ("Number packets band 1: " << m_band1->GetNPackets ()); + } + else if ((item = DynamicCast (m_band2->Dequeue ())) != 0) + { + NS_LOG_LOGIC ("Popped from band 2: " << item); + NS_LOG_LOGIC ("Number packets band 2: " << m_band2->GetNPackets ()); + } + else + { + NS_LOG_LOGIC ("Queue empty"); + } + return item; +} + +Ptr +PfifoFastQueueDisc::DoPeek (void) const +{ + NS_LOG_FUNCTION (this); + + Ptr item; + if (m_band0->GetNPackets ()) + { + item = DynamicCast (m_band0->Peek ()); + NS_LOG_LOGIC ("Peeked from band 0: " << item); + NS_LOG_LOGIC ("Number packets band 0: " << m_band0->GetNPackets ()); + } + else if (m_band1->GetNPackets ()) + { + item = DynamicCast (m_band1->Peek ()); + NS_LOG_LOGIC ("Peeked from band 1: " << item); + NS_LOG_LOGIC ("Number packets band 1: " << m_band1->GetNPackets ()); + } + else if (m_band2->GetNPackets ()) + { + item = DynamicCast (m_band2->Peek ()); + NS_LOG_LOGIC ("Peeked from band 2: " << item); + NS_LOG_LOGIC ("Number packets band 2: " << m_band2->GetNPackets ()); + } + + if (item == 0) + { + NS_LOG_LOGIC ("Queue empty"); + } + return item; +} + +uint32_t +PfifoFastQueueDisc::GetNPackets (uint32_t band) const +{ + NS_LOG_FUNCTION (this << band); + if (band == 0) + { + return m_band0->GetNPackets (); + } + else if (band == 1) + { + return m_band1->GetNPackets (); + } + else if (band == 2) + { + return m_band2->GetNPackets (); + } + else + { + NS_LOG_ERROR ("Invalid band " << band); + return 0; + } +} + +uint32_t +PfifoFastQueueDisc::Classify (Ptr item) const +{ + NS_LOG_FUNCTION (this << item); + bool found = false; + uint32_t band = 1; + + if (item->GetHeaderType () == QueueDiscItem::IPV4_HEADER) + { + const Ipv4Header & hdr4 = dynamic_cast (item->GetHeader ()); + if (m_trafficClassMode == QUEUE_MODE_TOS) + { + band = TosToBand (hdr4.GetTos ()); + found = true; + NS_LOG_DEBUG ("Found Ipv4 packet; TOS " << (uint16_t) hdr4.GetTos () << " band " << band); + } + else + { + band = DscpToBand (hdr4.GetDscp ()); + found = true; + NS_LOG_DEBUG ("Found Ipv4 packet; DSCP " << Ipv4Header::DscpTypeToString (hdr4.GetDscp ()) << " band " << band); + } + } + else + { + ///\todo classify IPv6 packets + NS_LOG_DEBUG ("Only able to classify IPv4 packets"); + } + if (!found) + { + NS_LOG_DEBUG ("Unable to classify; returning default band of " << band); + } + return band; +} + +uint32_t +PfifoFastQueueDisc::TosToBand (uint8_t tos) const +{ + NS_LOG_FUNCTION (this << (uint16_t) tos); + + uint32_t band = 1; + switch (tos) { + case 0x10 : + case 0x12 : + case 0x14 : + case 0x16 : + band = 0; + break; + case 0x0 : + case 0x4 : + case 0x6 : + case 0x18 : + case 0x1a : + case 0x1c : + case 0x1e : + band = 1; + break; + case 0x2 : + case 0x8 : + case 0xa : + case 0xc : + case 0xe : + band = 2; + break; + default : + NS_LOG_ERROR ("Invalid TOS " << (uint16_t) tos); + } + return band; +} + +uint32_t +PfifoFastQueueDisc::DscpToBand (Ipv4Header::DscpType dscpType) const +{ + NS_LOG_FUNCTION (this << Ipv4Header::DscpTypeToString (dscpType)); + + uint32_t band = 1; + switch (dscpType) { + case Ipv4Header::DSCP_EF : + case Ipv4Header::DSCP_AF13 : + case Ipv4Header::DSCP_AF23 : + case Ipv4Header::DSCP_AF33 : + case Ipv4Header::DSCP_AF43 : + case Ipv4Header::DscpDefault : + case Ipv4Header::DSCP_CS2 : + case Ipv4Header::DSCP_CS3 : + band = 1; + break; + case Ipv4Header::DSCP_AF11 : + case Ipv4Header::DSCP_AF21 : + case Ipv4Header::DSCP_AF31 : + case Ipv4Header::DSCP_AF41 : + case Ipv4Header::DSCP_CS1 : + band = 2; + break; + case Ipv4Header::DSCP_AF12 : + case Ipv4Header::DSCP_AF22 : + case Ipv4Header::DSCP_AF32 : + case Ipv4Header::DSCP_AF42 : + case Ipv4Header::DSCP_CS4 : + case Ipv4Header::DSCP_CS5 : + case Ipv4Header::DSCP_CS6 : + case Ipv4Header::DSCP_CS7 : + band = 0; + break; + default : + band = 1; + } + NS_LOG_DEBUG ("Band returned: " << band); + return band; +} + +} // namespace ns3 + diff --git a/src/traffic-control/model/pfifo-fast-queue-disc.h b/src/traffic-control/model/pfifo-fast-queue-disc.h new file mode 100644 index 00000000000..6b1e2c9816e --- /dev/null +++ b/src/traffic-control/model/pfifo-fast-queue-disc.h @@ -0,0 +1,167 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007, 2014 University of Washington + * + * 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 PFIFO_FAST_H +#define PFIFO_FAST_H + +#include "ns3/packet.h" +#include "ns3/queue-disc.h" +#include "ns3/ipv4-header.h" + +namespace ns3 { + +/** + * \ingroup traffic-control + * + * Linux pfifo_fast is the default priority queue enabled on Linux + * systems. Packets are enqueued in three FIFO droptail queues according + * to three priority bands based on their Type of Service bits or DSCP bits. + * + * The system behaves similar to three ns3::DropTail queues operating + * together, in which packets from higher priority bands are always + * dequeued before a packet from a lower priority band is dequeued. + * + * The queue depth set by the attributes is applicable to all three + * queue bands, similar to Linux behavior that each band is txqueuelen + * packets long. + * + * Packets are grouped into bands according to the IP TOS or DSCP. Packets + * without such a marking or without an IP header are grouped into band 1 + * (normal service). + * + * Two modes of operation are provided. pfifo_fast is originally based + * on RFC 1349 TOS byte definition: + * http://www.ietf.org/rfc/rfc1349.txt + * + * 0 1 2 3 4 5 6 7 + * +-----+-----+-----+-----+-----+-----+-----+-----+ + * | PRECEDENCE | TOS | MBZ | + * +-----+-----+-----+-----+-----+-----+-----+-----+ + * + * where MBZ stands for 'must be zero'. + * + * In the eight-bit legacy TOS byte, there were five lower bits for TOS + * and three upper bits for Precedence. Bit 7 was never used. Bits 6-7 + * are now repurposed for ECN. The below TOS values correspond to + * bits 3-7 in the TOS byte (i.e. including MBZ), omitting the precedence + * bits 0-2. + * + * TOS | Bits | Means | Linux Priority | Band + * -----|------|-------------------------|----------------|----- + * 0x0 | 0 | Normal Service | 0 Best Effort | 1 + * 0x2 | 1 | Minimize Monetary Cost | 1 Filler | 2 + * 0x4 | 2 | Maximize Reliability | 0 Best Effort | 1 + * 0x6 | 3 | mmc+mr | 0 Best Effort | 1 + * 0x8 | 4 | Maximize Throughput | 2 Bulk | 2 + * 0xa | 5 | mmc+mt | 2 Bulk | 2 + * 0xc | 6 | mr+mt | 2 Bulk | 2 + * 0xe | 7 | mmc+mr+mt | 2 Bulk | 2 + * 0x10 | 8 | Minimize Delay | 6 Interactive | 0 + * 0x12 | 9 | mmc+md | 6 Interactive | 0 + * 0x14 | 10 | mr+md | 6 Interactive | 0 + * 0x16 | 11 | mmc+mr+md | 6 Interactive | 0 + * 0x18 | 12 | mt+md | 4 Int. Bulk | 1 + * 0x1a | 13 | mmc+mt+md | 4 Int. Bulk | 1 + * 0x1c | 14 | mr+mt+md | 4 Int. Bulk | 1 + * 0x1e | 15 | mmc+mr+mt+md | 4 Int. Bulk | 1 + * + * When the queue is set to mode PfifoFastQueueDisc::QUEUE_MODE_TOS, the + * above values are used to map packets into bands, and IP precedence + * bits are disregarded. + * + * When the queue is set to mode PfifoFastQueueDisc::QUEUE_MODE_DSCP + * (the default), the following mappings are used. + * + * For DSCP, the following values are recommended for Linux in a patch + * to the netdev mailing list from Jesper Dangaard Brouer + * on 15 Sept 2014. CS* values I made up myself. + * + * DSCP | Hex | Means | Linux Priority | Band + * -----|------|----------------------------|----------------|----- + * EF | 0x2E | TC_PRIO_INTERACTIVE_BULK=4 | 4 Int. Bulk | 1 + * AF11 | 0x0A | TC_PRIO_BULK=2 | 2 Bulk | 2 + * AF21 | 0x12 | TC_PRIO_BULK=2 | 2 Bulk | 2 + * AF31 | 0x1A | TC_PRIO_BULK=2 | 2 Bulk | 2 + * AF41 | 0x22 | TC_PRIO_BULK=2 | 2 Bulk | 2 + * AF12 | 0x0C | TC_PRIO_INTERACTIVE=6 | 6 Interactive | 0 + * AF22 | 0x14 | TC_PRIO_INTERACTIVE=6 | 6 Interactive | 0 + * AF32 | 0x1C | TC_PRIO_INTERACTIVE=6 | 6 Interactive | 0 + * AF42 | 0x34 | TC_PRIO_INTERACTIVE=6 | 6 Interactive | 0 + * AF13 | 0x0E | TC_PRIO_INTERACTIVE_BULK=4 | 4 Int. Bulk | 1 + * AF23 | 0x16 | TC_PRIO_INTERACTIVE_BULK=4 | 4 Int. Bulk | 1 + * AF33 | 0x1E | TC_PRIO_INTERACTIVE_BULK=4 | 4 Int. Bulk | 1 + * AF43 | 0x26 | TC_PRIO_INTERACTIVE_BULK=4 | 4 Int. Bulk | 1 + * CS0 | 0x00 | TC_PRIO_BESTEFFORT | 0 Best Effort | 1 + * CS1 | 0x20 | TC_PRIO_FILLER | 1 Filler | 2 + * CS2 | 0x40 | TC_PRIO_BULK | 2 Bulk | 1 + * CS3 | 0x60 | TC_PRIO_INTERACTIVE_BULK | 4 Int. Bulk | 1 + * CS4 | 0x80 | TC_PRIO_INTERACTIVE | 6 Interactive | 0 + * CS5 | 0xA0 | TC_PRIO_INTERACTIVE | 6 Interactive | 0 + * CS6 | 0xC0 | TC_PRIO_INTERACTIVE | 6 Interactive | 0 + * CS7 | 0xE0 | TC_PRIO_CONTROL | 8 Control | 0 + * + */ +class PfifoFastQueueDisc : public QueueDisc { +public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + /** + * \brief PfifoFastQueueDisc constructor + * + * Creates a queue with a depth of 1000 packets per band by default + */ + PfifoFastQueueDisc (); + + virtual ~PfifoFastQueueDisc(); + + /** + * \brief Enumeration of modes of Ipv4 header traffic class semantics + */ + enum Ipv4TrafficClassMode + { + QUEUE_MODE_TOS, //!< use legacy TOS semantics to interpret TOS byte + QUEUE_MODE_DSCP, //!< use DSCP semantics to interpret TOS byte + }; + + /** + * \return The number of packets currently stored in one band of the queue + * \param band the band to check (0, 1, or 2) + */ + uint32_t GetNPackets (uint32_t band) const; + +private: + virtual bool DoEnqueue (Ptr item); + virtual Ptr DoDequeue (void); + virtual Ptr DoPeek (void) const; + + uint32_t Classify (Ptr item) const; + uint32_t TosToBand (uint8_t tos) const; + uint32_t DscpToBand (Ipv4Header::DscpType dscpType) const; + + Ptr m_band0; //!< the packets in band 0 + Ptr m_band1; //!< the packets in band 1 + Ptr m_band2; //!< the packets in band 2 + Ipv4TrafficClassMode m_trafficClassMode; //!< traffic class mode +}; + +} // namespace ns3 + +#endif /* PFIFO_FAST_H */ diff --git a/src/traffic-control/model/queue-disc.cc b/src/traffic-control/model/queue-disc.cc new file mode 100644 index 00000000000..f6ce91c2e33 --- /dev/null +++ b/src/traffic-control/model/queue-disc.cc @@ -0,0 +1,471 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007, 2014 University of Washington + * 2015 Universita' degli Studi di Napoli Federico II + * + * 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 "ns3/log.h" +#include "ns3/uinteger.h" +#include "queue-disc.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("QueueDisc"); + +QueueDiscItem::QueueDiscItem (Ptr p, const Ipv4Header& hdr, const Address& addr, uint16_t protocol, uint8_t txq) + : QueueItem (p), + m_ipv4Header (hdr), + m_headerType (IPV4_HEADER), + m_address (addr), + m_protocol (protocol), + m_txq (txq) +{ +} + +QueueDiscItem::QueueDiscItem (Ptr p, const Ipv6Header& hdr, const Address& addr, uint16_t protocol, uint8_t txq) + : QueueItem (p), + m_ipv6Header (hdr), + m_headerType (IPV6_HEADER), + m_address (addr), + m_protocol (protocol), + m_txq (txq) +{ +} + +QueueDiscItem::~QueueDiscItem() +{ + NS_LOG_FUNCTION (this); +} + +QueueDiscItem::HeaderType +QueueDiscItem::GetHeaderType (void) const +{ + return m_headerType; +} + +const Header & +QueueDiscItem::GetHeader (void) const +{ + if (m_headerType == IPV4_HEADER) + { + return m_ipv4Header; + } + if (m_headerType == IPV6_HEADER) + { + return m_ipv6Header; + } + NS_ASSERT (false); +} + +Address +QueueDiscItem::GetAddress (void) const +{ + return m_address; +} + +uint16_t +QueueDiscItem::GetProtocol (void) const +{ + return m_protocol; +} + +uint16_t +QueueDiscItem::GetTxq (void) const +{ + return m_txq; +} + +void +QueueDiscItem::Print (std::ostream& os) const +{ + os << GetPacket () << " " + << "Dst addr " << m_address << " " + << "proto " << m_protocol << " " + << "txq " << m_txq + ; +} + + +NS_OBJECT_ENSURE_REGISTERED (QueueDisc); + +TypeId QueueDisc::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::QueueDisc") + .SetParent () + .AddAttribute ("Quota", "The maximum number of packets dequeued in a qdisc run", + UintegerValue (DEFAULT_QUOTA), + MakeUintegerAccessor (&QueueDisc::SetQuota, + &QueueDisc::GetQuota), + MakeUintegerChecker ()) + .AddTraceSource ("Enqueue", "Enqueue a packet in the queue disc", + MakeTraceSourceAccessor (&QueueDisc::m_traceEnqueue), + "ns3::Packet::TracedCallback") + .AddTraceSource ("Dequeue", "Dequeue a packet from the queue disc", + MakeTraceSourceAccessor (&QueueDisc::m_traceDequeue), + "ns3::Packet::TracedCallback") + .AddTraceSource ("Requeue", "Requeue a packet in the queue disc", + MakeTraceSourceAccessor (&QueueDisc::m_traceRequeue), + "ns3::Packet::TracedCallback") + .AddTraceSource ("Drop", "Drop a packet stored in the queue disc", + MakeTraceSourceAccessor (&QueueDisc::m_traceDrop), + "ns3::Packet::TracedCallback") + .AddTraceSource ("PacketsInQueue", + "Number of packets currently stored in the queue disc", + MakeTraceSourceAccessor (&QueueDisc::m_nPackets), + "ns3::TracedValueCallback::Uint32") + .AddTraceSource ("BytesInQueue", + "Number of bytes currently stored in the queue disc", + MakeTraceSourceAccessor (&QueueDisc::m_nBytes), + "ns3::TracedValueCallback::Uint32") + ; + return tid; +} + +QueueDisc::QueueDisc () + : m_nPackets (0), + m_nBytes (0), + m_nTotalReceivedPackets (0), + m_nTotalReceivedBytes (0), + m_nTotalDroppedPackets (0), + m_nTotalDroppedBytes (0), + m_nTotalRequeuedPackets (0), + m_nTotalRequeuedBytes (0), + m_running (false) +{ + NS_LOG_FUNCTION (this); +} + +uint32_t +QueueDisc::GetNPackets () const +{ + NS_LOG_FUNCTION (this); + return m_nPackets; +} + +uint32_t +QueueDisc::GetNBytes (void) const +{ + NS_LOG_FUNCTION (this); + return m_nBytes; +} + +uint32_t +QueueDisc::GetTotalReceivedPackets (void) const +{ + NS_LOG_FUNCTION (this); + return m_nTotalReceivedPackets; +} + +uint32_t +QueueDisc::GetTotalReceivedBytes (void) const +{ + NS_LOG_FUNCTION (this); + return m_nTotalReceivedBytes; +} + +uint32_t +QueueDisc::GetTotalDroppedPackets (void) const +{ + NS_LOG_FUNCTION (this); + return m_nTotalDroppedPackets; +} + +uint32_t +QueueDisc:: GetTotalDroppedBytes (void) const +{ + NS_LOG_FUNCTION (this); + return m_nTotalDroppedBytes; +} + +uint32_t +QueueDisc::GetTotalRequeuedPackets (void) const +{ + NS_LOG_FUNCTION (this); + return m_nTotalRequeuedPackets; +} + +uint32_t +QueueDisc:: GetTotalRequeuedBytes (void) const +{ + NS_LOG_FUNCTION (this); + return m_nTotalRequeuedBytes; +} + +void +QueueDisc::SetNetDeviceQueue (Ptr devQueue) +{ + NS_LOG_FUNCTION (this << devQueue); + m_devQueue = devQueue; +} + +Ptr +QueueDisc::GetNetDeviceQueue (void) const +{ + NS_LOG_FUNCTION (this); + return m_devQueue; +} + +void +QueueDisc::SetWakeCbOnTxQueue (void) +{ + if (m_devQueue == 0) + { + NS_LOG_WARN ("Cannot set the wake callback because m_devQueue is not set."); + return; + } + + m_devQueue->SetWakeCallback (MakeCallback (&QueueDisc::Run, this)); +} + +void +QueueDisc::SetWakeCbOnAllTxQueues (void) +{ + if (m_devQueue == 0) + { + NS_LOG_WARN ("Cannot set the wake callback because m_devQueue is not set."); + return; + } + + Ptr devQueue; + for (uint8_t i = 0; i < m_devQueue->GetDevice ()->GetTxQueuesN (); i++) + { + devQueue = m_devQueue->GetDevice ()->GetTxQueue (i); + devQueue->SetWakeCallback (MakeCallback (&QueueDisc::Run, this)); + } +} + +void +QueueDisc::SetQuota (const uint32_t quota) +{ + NS_LOG_FUNCTION (this << quota); + m_quota = quota; +} + +uint32_t +QueueDisc::GetQuota (void) const +{ + NS_LOG_FUNCTION (this); + return m_quota; +} + +void +QueueDisc::Drop (Ptr p) +{ + NS_LOG_FUNCTION (this << p); + + m_nTotalDroppedPackets++; + m_nTotalDroppedBytes += p->GetSize (); + + NS_LOG_LOGIC ("m_traceDrop (p)"); + m_traceDrop (p); +} + +bool +QueueDisc::Enqueue (Ptr item) +{ + NS_LOG_FUNCTION (this << item); + bool ret = DoEnqueue (item); + if (ret) + { + Ptr p = item->GetPacket (); + m_nPackets++; + m_nBytes += p->GetSize (); + m_nTotalReceivedPackets++; + m_nTotalReceivedBytes += p->GetSize (); + + NS_LOG_LOGIC ("m_traceEnqueue (p)"); + m_traceEnqueue (p); + } + + return ret; +} + +Ptr +QueueDisc::Dequeue (void) +{ + NS_LOG_FUNCTION (this); + + Ptr item; + item = DoDequeue (); + + if (item != 0) + { + Ptr p = item->GetPacket (); + m_nPackets--; + m_nBytes -= p->GetSize (); + + NS_LOG_LOGIC ("m_traceDequeue (p)"); + m_traceDequeue (p); + } + + return item; +} + +Ptr +QueueDisc::Peek (void) const +{ + NS_LOG_FUNCTION (this); + return DoPeek (); +} + +void +QueueDisc::Run (void) +{ + NS_LOG_FUNCTION (this); + + if (RunBegin ()) + { + uint32_t quota = m_quota; + while (Restart ()) + { + quota -= 1; + if (quota <= 0) + { + /// \todo netif_schedule (q); + break; + } + } + RunEnd (); + } +} + +bool +QueueDisc::RunBegin (void) +{ + NS_LOG_FUNCTION (this); + if (m_running) + { + return false; + } + + m_running = true; + return true; +} + +void +QueueDisc::RunEnd (void) +{ + NS_LOG_FUNCTION (this); + m_running = false; +} + +bool +QueueDisc::Restart (void) +{ + NS_LOG_FUNCTION (this); + Ptr item = DequeuePacket(); + if (item == 0) + { + NS_LOG_LOGIC ("No packet to send"); + return false; + } + + return Transmit (item); +} + +Ptr +QueueDisc::DequeuePacket () +{ + NS_LOG_FUNCTION (this); + NS_ASSERT (m_devQueue); + Ptr item; + + // First check if there is a requeued packet + if (m_requeued != 0) + { + // If the queue where the requeued packet is destined to is not stopped, return + // the requeued packet; otherwise, return an empty packet. + // Note that this function is only called on root queue discs and hence + // m_devQueue does not point to the transmission queue associated to this + // queue disc. + if (!m_devQueue->GetDevice ()->GetTxQueue (m_requeued->GetTxq ())->IsStopped ()) + { + item = m_requeued; + m_requeued = 0; + + m_nPackets--; + m_nBytes -= item->GetPacket ()->GetSize (); + + NS_LOG_LOGIC ("m_traceDequeue (p)"); + m_traceDequeue (item->GetPacket ()); + } + } + else + { + // If the device is multi-queue (actually, Linux checks if the queue disc has + // multiple queues), ask the queue disc to dequeue a packet (a multi-queue aware + // queue disc should try not to dequeue a packet destined to a stopped queue). + // Otherwise, ask the queue disc to dequeue a packet only if the (unique) queue + // is not stopped. + if (m_devQueue->GetDevice ()->GetTxQueuesN ()>1 || !m_devQueue->IsStopped ()) + { + item = Dequeue (); + // If the item is not null, add the IP header to the packet. + if (item != 0) + { + item->GetPacket ()->AddHeader (item->GetHeader ()); + } + // Here, Linux tries bulk dequeues + } + } + return item; +} + +void +QueueDisc::Requeue (Ptr item) +{ + NS_LOG_FUNCTION (this << item); + m_requeued = item; + /// \todo netif_schedule (q); + + Ptr p = item->GetPacket (); + m_nPackets++; // it's still part of the queue + m_nBytes += p->GetSize (); + m_nTotalRequeuedPackets++; + m_nTotalRequeuedBytes += p->GetSize (); + + NS_LOG_LOGIC ("m_traceRequeue (p)"); + m_traceRequeue (p); +} + +bool +QueueDisc::Transmit (Ptr item) +{ + NS_LOG_FUNCTION (this << item); + NS_ASSERT (m_devQueue); + bool ret = false; + + if (!m_devQueue->GetDevice ()->GetTxQueue (item->GetTxq ())->IsStopped ()) + { + ret = m_devQueue->GetDevice ()->Send (item->GetPacket (), item->GetAddress (), item->GetProtocol ()); + } + + // If the transmission did not happen or failed, requeue the item + if (!ret) + { + Requeue (item); + } + + // If the transmission succeeded but now the queue is stopped, return false + if (ret && m_devQueue->GetDevice ()->GetTxQueue (item->GetTxq ())->IsStopped ()) + { + ret = false; + } + + return ret; +} + +} // namespace ns3 diff --git a/src/traffic-control/model/queue-disc.h b/src/traffic-control/model/queue-disc.h new file mode 100644 index 00000000000..20ed9a986ec --- /dev/null +++ b/src/traffic-control/model/queue-disc.h @@ -0,0 +1,355 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007, 2014 University of Washington + * 2015 Universita' degli Studi di Napoli Federico II + * + * 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 QUEUE_DISC_H +#define QUEUE_DISC_H + +#include "ns3/packet.h" +#include "ns3/object.h" +#include "ns3/ipv4-header.h" +#include "ns3/ipv6-header.h" +#include "ns3/net-device.h" +#include "ns3/traced-value.h" +#include + +namespace ns3 { + +/** + * \ingroup internet + * + * QueueDiscItem represents the kind of items that are stored in a queue + * disc. It is derived from QueueItem (which only consists of a Ptr) + * to additionally store the IP header (that will be added when the packet + * is dequeued from the queue disc), the destination MAC address, the + * protocol number and the transmission queue index, + */ +class QueueDiscItem : public QueueItem { +public: + /** + * \brief Create a queue disc item containing an IPv4 packet. + * \param p the packet included in the created item. + * \param hdr the IPv4 header + * \param addr the destination MAC address + * \param protocol the protocol number + * \param txq the transmission queue index + */ + QueueDiscItem (Ptr p, const Ipv4Header & hdr, const Address & addr, uint16_t protocol, uint8_t txq); + + /** + * \brief Create a queue disc item containing an IPv6 packet. + * \param p the packet included in the created item. + * \param hdr the IPv6 header + * \param addr the destination MAC address + * \param protocol the protocol number + * \param txq the transmission queue index + */ + QueueDiscItem (Ptr p, const Ipv6Header & hdr, const Address & addr, uint16_t protocol, uint8_t txq); + + virtual ~QueueDiscItem (); + + /** + * \brief Enumeration of the header types. + * + */ + enum HeaderType + { + IPV4_HEADER, + IPV6_HEADER + }; + + /** + * \return the type of IP header included in this item. + */ + HeaderType GetHeaderType (void) const; + + /** + * \return the IP header included in this item. + */ + const Header & GetHeader (void) const; + + /** + * \return the MAC address included in this item. + */ + Address GetAddress (void) const; + + /** + * \return the protocol included in this item. + */ + uint16_t GetProtocol (void) const; + + /** + * \return the transmission queue index included in this item. + */ + uint16_t GetTxq (void) const; + + /** + * \brief Print the item contents. + * \param os output stream in which the data should be printed. + */ + virtual void Print (std::ostream &os) const; + +private: + /** + * \brief Default constructor + * + * Defined and unimplemented to avoid misuse + */ + QueueDiscItem (); + /** + * \brief Copy constructor + * + * Defined and unimplemented to avoid misuse + */ + QueueDiscItem (const QueueDiscItem &); + /** + * \brief Assignment operator + * + * Defined and unimplemented to avoid misuse + * \returns + */ + QueueDiscItem &operator = (const QueueDiscItem &); + + Ipv4Header m_ipv4Header; + Ipv6Header m_ipv6Header; + HeaderType m_headerType; + Address m_address; + uint16_t m_protocol; + uint8_t m_txq; +}; + +/** + * \ingroup internet + * + * QueueDisc is a base class providing the interface and implementing + * the operations common to all the queueing disciplines. Child classes + * need to implement the methods used to enqueue a packet (DoEnqueue), + * dequeue a single packet (DoDequeue), get a copy of the next packet + * to extract (DoPeek), plus methods to classify enqueued packets in + * case they manage multiple queues internally. + * + * The root queue disc must be aggregated to the NetDevice it is attached to. + * A multi-queue aware (root) queue disc, i.e., a queue disc that is aware + * of the number of (hardware) transmission queues used by the device, can + * aggregate a child queue disc to each of the NetDeviceQueues. + * Thus, in case of a root queue disc, the m_devQueue member points to one + * of the transmission queues of the device (typically the first one). + * In case of a queue disc that is a child of a multi-queue aware queue + * disc, the m_devQueue member points to the transmission queue of the device + * it is aggregated to. + * + * When setting up a root qdisc, a wake callback must be set on each of the + * netdevice queues pointing to the Run method of the root queue disc. This is + * done by calling the SetWakeCbOnAllTxQueues method. Multi-queue aware queue + * discs can then override such a configuration by setting a wake callback on + * each netdevice queue pointing to the Run method of the child queue disc + * created to handle that netdevice queue. To this end, the SetWakeCbOnTxQueue + * method can be exploited. + * + * When the Traffic Control layer receives a packet from the upper layers, it + * enqueues such packet into the root queue disc, by calling Enqueue, and + * requests the root queue disc to extract a train of packets by calling Run. + * If the queue disc contains child queue discs (it might be multi-queue aware + * or not), the root queue qdisc calls the Enqueue and Dequeue methods, + * respectively, of the selected child classes to enqueue and dequeue packets. + * Hence, Run is only called by the Traffic Control layer on the root queue disc. + * + * The design and implementation of this class is heavily inspired by Linux. + */ +class QueueDisc : public Object { +public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + + QueueDisc (); + + uint32_t GetNPackets (void) const; + + uint32_t GetNBytes (void) const; + + uint32_t GetTotalReceivedPackets (void) const; + + uint32_t GetTotalReceivedBytes (void) const; + + uint32_t GetTotalDroppedPackets (void) const; + + uint32_t GetTotalDroppedBytes (void) const; + + uint32_t GetTotalRequeuedPackets (void) const; + + uint32_t GetTotalRequeuedBytes (void) const; + + /** + * Set the NetDeviceQueue associated with this queue discipline. + * \param devQueue the NetDeviceQueue associated with this queue discipline. + */ + void SetNetDeviceQueue (Ptr devQueue); + + /** + * \return the NetDeviceQueue associated with this queue discipline. + */ + Ptr GetNetDeviceQueue (void) const; + + /** + * Set the wake callback on the NetDeviceQueue associated with this queue + * discipline, if any, and do nothing otherwise. + */ + void SetWakeCbOnTxQueue (void); + + /** + * Set the wake callback on all the transmission queues of the device associated + * with this queue discipline, if any, and do nothing otherwise. + */ + void SetWakeCbOnAllTxQueues (void); + + virtual void SetQuota (const uint32_t quota); + virtual uint32_t GetQuota (void) const; + + /** + * Pass a packet to store to the queue discipline. This function only updates + * the statistics and calls the (private) DoEnqueue function, which must be + * implemented by derived classes. + * \param item item to enqueue + * \return True if the operation was successful; false otherwise + */ + bool Enqueue (Ptr item); + + /** + * Request the queue discipline to extract a packet. This function only updates + * the statistics and calls the (private) DoDequeue function, which must be + * implemented by derived classes. + * \return 0 if the operation was not successful; the item otherwise. + */ + Ptr Dequeue (void); + + /** + * Get a copy of the next packet the queue discipline will extract, without + * actually extracting the packet. This function only calls the (private) + * DoPeek function, which must be implemented by derived classes. + * \return 0 if the operation was not successful; the item otherwise. + */ + Ptr Peek (void) const; + + /** + * Modelled after the Linux function __qdisc_run (net/sched/sch_generic.c) + * Dequeues multiple packets, until a quota is exceeded or sending a packet + * to the device failed. + */ + void Run (void); + +protected: + /** + * \brief Drop a packet + * \param packet packet that was dropped + * This method is called by subclasses to notify parent (this class) of packet drops. + */ + void Drop (Ptr packet); + +private: + + /** + * This function actually enqueues a packet into the queue disc. + * \param item item to enqueue + * \return True if the operation was successful; false otherwise + */ + virtual bool DoEnqueue (Ptr item) = 0; + + /** + * This function actually extracts a packet from the queue disc. + * \return 0 if the operation was not successful; the item otherwise. + */ + virtual Ptr DoDequeue (void) = 0; + + /** + * This function returns a copy of the next packet the queue disc will extract. + * \return 0 if the operation was not successful; the packet otherwise. + */ + virtual Ptr DoPeek (void) const = 0; + + /** + * Modelled after the Linux function qdisc_run_begin (include/net/sch_generic.h). + * \return false if the qdisc is already running; otherwise, set the qdisc as running and return true. + */ + bool RunBegin (void); + + /** + * Modelled after the Linux function qdisc_run_end (include/net/sch_generic.h). + * Set the qdisc as not running. + */ + void RunEnd (void); + + /** + * Modelled after the Linux function qdisc_restart (net/sched/sch_generic.c) + * Dequeue a packet (by calling DequeuePacket) and send it to the device (by calling Transmit). + * \return true if a packet is successfully sent to the device. + */ + bool Restart (void); + + /** + * Modelled after the Linux function dequeue_skb (net/sched/sch_generic.c) + * \return the requeued packet, if any, or the packet dequeued by the queue disc, otherwise. + */ + Ptr DequeuePacket (void); + + /** + * Modelled after the Linux function dev_requeue_skb (net/sched/sch_generic.c) + * Requeues a packet whose transmission failed. + * \param p the packet to requeue + */ + void Requeue (Ptr p); + + /** + * Modelled after the Linux function sch_direct_xmit (net/sched/sch_generic.c) + * Sends a packet to the device and requeues it in case transmission fails. + * \param p the packet to transmit + * \return true if the transmission succeeded and the queue is not stopped + */ + bool Transmit (Ptr p); + + static const uint32_t DEFAULT_QUOTA = 64; //!< Default quota (as in /proc/sys/net/core/dev_weight) + + TracedValue m_nPackets; //!< Number of packets in the queue + TracedValue m_nBytes; //!< Number of bytes in the queue + + uint32_t m_nTotalReceivedPackets; //!< Total received packets + uint32_t m_nTotalReceivedBytes; //!< Total received bytes + uint32_t m_nTotalDroppedPackets; //!< Total dropped packets + uint32_t m_nTotalDroppedBytes; //!< Total dropped bytes + uint32_t m_nTotalRequeuedPackets; //!< Total requeued packets + uint32_t m_nTotalRequeuedBytes; //!< Total requeued bytes + uint32_t m_quota; //!< Maximum number of packets dequeued in a qdisc run + Ptr m_devQueue; //!< The NetDeviceQueue associated with this queue discipline + bool m_running; //!< The queue disc is performing multiple dequeue operations + Ptr m_requeued; //!< The last packet that failed to be transmitted + + /// Traced callback: fired when a packet is enqueued + TracedCallback > m_traceEnqueue; + /// Traced callback: fired when a packet is dequeued + TracedCallback > m_traceDequeue; + /// Traced callback: fired when a packet is requeued + TracedCallback > m_traceRequeue; + /// Traced callback: fired when a packet is dropped + TracedCallback > m_traceDrop; +}; + +} // namespace ns3 + +#endif /* QueueDisc */ 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 00000000000..db37d4d0751 --- /dev/null +++ b/src/traffic-control/model/traffic-control-layer.cc @@ -0,0 +1,156 @@ +/* -*- 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" +#include "ns3/queue-disc.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 Node::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 (Node::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 Header & hdr, + 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); + + // determine the transmission queue of the device where the packet will be enqueued + uint8_t txq = device->GetSelectedQueue (packet); + + Ptr qDisc = device->GetObject (); + + if (qDisc == 0) + { + // The device has no attached queue disc, thus add the header to the packet and + // send it directly to the device if the selected queue is not stopped + if (!device->GetTxQueue (txq)->IsStopped ()) + { + packet->AddHeader (hdr); + device->Send (packet, dest, protocolNumber); + } + } + else + { + // determine the header type (IPv4 or IPv6) to create the queue disc item + Ptr item; + try + { + const Ipv4Header & ipv4Header = dynamic_cast (hdr); + item = Create (packet, ipv4Header, dest, protocolNumber, txq); + } + catch (std::bad_cast) + { + try + { + const Ipv6Header & ipv6Header = dynamic_cast (hdr); + item = Create (packet, ipv6Header, dest, protocolNumber, txq); + } + catch (std::bad_cast) + { + NS_ASSERT (false); + } + } + + qDisc->Enqueue (item); + qDisc->Run (); + } +} + +} // 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 00000000000..8e5fce56031 --- /dev/null +++ b/src/traffic-control/model/traffic-control-layer.h @@ -0,0 +1,154 @@ +/* -*- 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" +#include "ns3/header.h" + +namespace ns3 { + +class Packet; + +/** + * \ingroup traffic-control + * + * \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 calls the Enqueue method of the QueueDisc associated + * with the device. The Dequeue method of the QueueDisc finally calls the Send + * method of the 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 Header & hdr, + const Address& dest, uint16_t protocolNumber); + +protected: + Node::ProtocolHandlerList m_handlers; //!< List of upper-layer handlers +}; + +} // namespace ns3 +#endif // TRAFFICCONTROLLAYER_H diff --git a/src/traffic-control/test/pfifo-fast-queue-disc-test-suite.cc b/src/traffic-control/test/pfifo-fast-queue-disc-test-suite.cc new file mode 100644 index 00000000000..fe5586f2577 --- /dev/null +++ b/src/traffic-control/test/pfifo-fast-queue-disc-test-suite.cc @@ -0,0 +1,332 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2014 University of Washington + * + * 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 "ns3/test.h" +#include "ns3/pfifo-fast-queue-disc.h" +#include "ns3/drop-tail-queue.h" +#include "ns3/ipv4-header.h" +#include "ns3/enum.h" +#include "ns3/uinteger.h" +#include "ns3/pointer.h" +#include "ns3/object-factory.h" + +using namespace ns3; + +/** + * This class tests that each possible TOS is enqueued in the right band + */ +class PfifoFastQueueDiscTosPrioritization : public TestCase +{ +public: + PfifoFastQueueDiscTosPrioritization (); + virtual ~PfifoFastQueueDiscTosPrioritization (); + +private: + virtual void DoRun (void); + Ptr CreatePacketWithTos (uint8_t tos); + void TestTosValue (Ptr queue, uint8_t tos, uint32_t band); +}; + +PfifoFastQueueDiscTosPrioritization::PfifoFastQueueDiscTosPrioritization () + : TestCase ("Test TOS-based prioritization") +{ +} + +PfifoFastQueueDiscTosPrioritization::~PfifoFastQueueDiscTosPrioritization () +{ +} + +Ptr +PfifoFastQueueDiscTosPrioritization::CreatePacketWithTos (uint8_t tos) +{ + Ptr p = Create (100); + Ipv4Header ipHeader; + ipHeader.SetPayloadSize (100); + ipHeader.SetTos (tos); + ipHeader.SetProtocol (6); + p->AddHeader (ipHeader); + return p; +} + +void +PfifoFastQueueDiscTosPrioritization::TestTosValue (Ptr queue, uint8_t tos, uint32_t band) +{ + Ptr p = CreatePacketWithTos (tos); + Ipv4Header ipHeader; + p->RemoveHeader (ipHeader); + Address dest; + Ptr item = Create (p, ipHeader, dest, 0, 0); + queue->Enqueue (item); + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (band), 1, "enqueued to unexpected band"); + item = queue->Dequeue (); + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (band), 0, "unable to dequeue"); +} + +void +PfifoFastQueueDiscTosPrioritization::DoRun (void) +{ + Ptr queue = CreateObject (); + bool ok = queue->SetAttributeFailSafe ("Mode", EnumValue (PfifoFastQueueDisc::QUEUE_MODE_TOS)); + NS_TEST_ASSERT_MSG_EQ (ok, true, "unable to set attribute"); + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (0), 0, "initialized non-zero"); + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (1), 0, "initialized non-zero"); + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (2), 0, "initialized non-zero"); + + TestTosValue (queue, 0x0, 1); + TestTosValue (queue, 0x2, 2); + TestTosValue (queue, 0x4, 1); + TestTosValue (queue, 0x6, 1); + TestTosValue (queue, 0x8, 2); + TestTosValue (queue, 0xa, 2); + TestTosValue (queue, 0xc, 2); + TestTosValue (queue, 0xe, 2); + TestTosValue (queue, 0x10, 0); + TestTosValue (queue, 0x12, 0); + TestTosValue (queue, 0x14, 0); + TestTosValue (queue, 0x16, 0); + TestTosValue (queue, 0x18, 1); + TestTosValue (queue, 0x1a, 1); + TestTosValue (queue, 0x1c, 1); + TestTosValue (queue, 0x1e, 1); +} + +/** + * This class tests that each possible DSCP is enqueued in the right band + */ +class PfifoFastQueueDiscDscpPrioritization : public TestCase +{ +public: + PfifoFastQueueDiscDscpPrioritization (); + virtual ~PfifoFastQueueDiscDscpPrioritization (); + +private: + virtual void DoRun (void); + Ptr CreatePacketWithDscp (Ipv4Header::DscpType dscp); + void TestDscpValue (Ptr queue, Ipv4Header::DscpType dscp, uint32_t band); +}; + +PfifoFastQueueDiscDscpPrioritization::PfifoFastQueueDiscDscpPrioritization () + : TestCase ("Test DSCP-based prioritization") +{ +} + +PfifoFastQueueDiscDscpPrioritization::~PfifoFastQueueDiscDscpPrioritization () +{ +} + +Ptr +PfifoFastQueueDiscDscpPrioritization::CreatePacketWithDscp (Ipv4Header::DscpType dscp) +{ + Ptr p = Create (100); + Ipv4Header ipHeader; + ipHeader.SetPayloadSize (100); + ipHeader.SetProtocol (6); + ipHeader.SetDscp (dscp); + p->AddHeader (ipHeader); + return p; +} + +void +PfifoFastQueueDiscDscpPrioritization::TestDscpValue (Ptr queue, Ipv4Header::DscpType dscp, uint32_t band) +{ + Ptr p = CreatePacketWithDscp (dscp); + Ipv4Header ipHeader; + p->RemoveHeader (ipHeader); + Address dest; + Ptr item = Create (p, ipHeader, dest, 0, 0); + queue->Enqueue (item); + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (band), 1, "enqueued to unexpected band"); + item = queue->Dequeue (); + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (band), 0, "unable to dequeue"); +} + +void +PfifoFastQueueDiscDscpPrioritization::DoRun (void) +{ + Ptr queue = CreateObject (); + bool ok = queue->SetAttributeFailSafe ("Mode", EnumValue (PfifoFastQueueDisc::QUEUE_MODE_DSCP)); + NS_TEST_ASSERT_MSG_EQ (ok, true, "unable to set attribute"); + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (0), 0, "initialized non-zero"); + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (1), 0, "initialized non-zero"); + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (2), 0, "initialized non-zero"); + + TestDscpValue (queue, Ipv4Header::DscpDefault, 1); + TestDscpValue (queue, Ipv4Header::DSCP_EF, 1); + TestDscpValue (queue, Ipv4Header::DSCP_AF11, 2); + TestDscpValue (queue, Ipv4Header::DSCP_AF21, 2); + TestDscpValue (queue, Ipv4Header::DSCP_AF31, 2); + TestDscpValue (queue, Ipv4Header::DSCP_AF41, 2); + TestDscpValue (queue, Ipv4Header::DSCP_AF12, 0); + TestDscpValue (queue, Ipv4Header::DSCP_AF22, 0); + TestDscpValue (queue, Ipv4Header::DSCP_AF32, 0); + TestDscpValue (queue, Ipv4Header::DSCP_AF42, 0); + TestDscpValue (queue, Ipv4Header::DSCP_AF13, 1); + TestDscpValue (queue, Ipv4Header::DSCP_AF23, 1); + TestDscpValue (queue, Ipv4Header::DSCP_AF33, 1); + TestDscpValue (queue, Ipv4Header::DSCP_AF43, 1); + TestDscpValue (queue, Ipv4Header::DSCP_CS1, 2); + TestDscpValue (queue, Ipv4Header::DSCP_CS2, 1); + TestDscpValue (queue, Ipv4Header::DSCP_CS3, 1); + TestDscpValue (queue, Ipv4Header::DSCP_CS4, 0); + TestDscpValue (queue, Ipv4Header::DSCP_CS5, 0); + TestDscpValue (queue, Ipv4Header::DSCP_CS6, 0); + TestDscpValue (queue, Ipv4Header::DSCP_CS7, 0); +} + +/** + * This class tests that each band is txqueuelen deep + */ +class PfifoFastQueueDiscOverflow : public TestCase +{ +public: + PfifoFastQueueDiscOverflow (); + virtual ~PfifoFastQueueDiscOverflow (); + +private: + virtual void DoRun (void); + void AddPacket (Ptr queue, Ipv4Header::DscpType dscp); +}; + +PfifoFastQueueDiscOverflow::PfifoFastQueueDiscOverflow () + : TestCase ("Test queue overflow") +{ +} + +PfifoFastQueueDiscOverflow::~PfifoFastQueueDiscOverflow () +{ +} + +void +PfifoFastQueueDiscOverflow::AddPacket (Ptr queue, Ipv4Header::DscpType dscp) +{ + Ptr p = Create (100); + Ipv4Header ipHeader; + ipHeader.SetPayloadSize (100); + ipHeader.SetProtocol (6); + ipHeader.SetDscp (dscp); + Address dest; + Ptr item = Create (p, ipHeader, dest, 0, 0); + queue->Enqueue (item); +} + +void +PfifoFastQueueDiscOverflow::DoRun (void) +{ + Ptr band0 = CreateObjectWithAttributes ("MaxPackets", UintegerValue (2)); + Ptr band1 = CreateObjectWithAttributes ("MaxPackets", UintegerValue (2)); + Ptr band2 = CreateObjectWithAttributes ("MaxPackets", UintegerValue (2)); + Ptr queue = CreateObjectWithAttributes ("Band0", PointerValue (band0), + "Band1", PointerValue (band1), + "Band2", PointerValue (band2)); + bool ok = queue->SetAttributeFailSafe ("Mode", EnumValue (PfifoFastQueueDisc::QUEUE_MODE_DSCP)); + NS_TEST_ASSERT_MSG_EQ (ok, true, "unable to set attribute"); + + // Add two packets per each band + AddPacket (queue, Ipv4Header::DSCP_AF42); // 0 + AddPacket (queue, Ipv4Header::DSCP_AF42); // 0 + AddPacket (queue, Ipv4Header::DSCP_AF13); // 1 + AddPacket (queue, Ipv4Header::DSCP_AF13); // 1 + AddPacket (queue, Ipv4Header::DSCP_AF11); // 2 + AddPacket (queue, Ipv4Header::DSCP_AF11); // 2 + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (0), 2, "unexpected queue depth"); + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (1), 2, "unexpected queue depth"); + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (2), 2, "unexpected queue depth"); + NS_TEST_ASSERT_MSG_EQ (queue->QueueDisc::GetNPackets (), 6, "unexpected queue depth"); + // Add a third packet to each band + AddPacket (queue, Ipv4Header::DSCP_AF42); // 0 + AddPacket (queue, Ipv4Header::DSCP_AF13); // 1 + AddPacket (queue, Ipv4Header::DSCP_AF11); // 2 + // Bands should still have two packets each + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (0), 2, "unexpected queue depth"); + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (1), 2, "unexpected queue depth"); + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (2), 2, "unexpected queue depth"); + NS_TEST_ASSERT_MSG_EQ (queue->QueueDisc::GetNPackets (), 6, "unexpected queue depth"); +} + +/** + * This class tests that non-IP packets are handled by placing them into + * band 1 + */ +class PfifoFastQueueDiscNonIpHeader : public TestCase +{ +public: + PfifoFastQueueDiscNonIpHeader (); + virtual ~PfifoFastQueueDiscNonIpHeader (); + +private: + virtual void DoRun (void); +}; + +PfifoFastQueueDiscNonIpHeader::PfifoFastQueueDiscNonIpHeader () + : TestCase ("Test queue with non IP header") +{ +} + +PfifoFastQueueDiscNonIpHeader::~PfifoFastQueueDiscNonIpHeader () +{ +} + +void +PfifoFastQueueDiscNonIpHeader::DoRun (void) +{ + // all packets with non-IP headers should enqueue in band 1 + Ptr queue = CreateObject (); + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (1), 0, "unexpected queue depth"); + Ptr p; + p = Create (); + Ptr item; + Ipv6Header ipv6Header; + Address dest; + item = Create (p, ipv6Header, dest, 0, 0); + queue->Enqueue (item); + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (1), 1, "unexpected queue depth"); + p = Create (reinterpret_cast ("hello, world"), 12); + item = Create (p, ipv6Header, dest, 0, 0); + queue->Enqueue (item); + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (1), 2, "unexpected queue depth"); + p = Create (100); + uint8_t *buf = new uint8_t[100]; + uint8_t counter = 0; + for (uint32_t i = 0; i < 100; i++) + { + buf[i] = counter++; + } + p->CopyData (buf, 100); + item = Create (p, ipv6Header, dest, 0, 0); + queue->Enqueue (item); + NS_TEST_ASSERT_MSG_EQ (queue->GetNPackets (1), 3, "unexpected queue depth"); + delete[] buf; +} + +class PfifoFastQueueDiscTestSuite : public TestSuite +{ +public: + PfifoFastQueueDiscTestSuite (); +}; + +PfifoFastQueueDiscTestSuite::PfifoFastQueueDiscTestSuite () + : TestSuite ("pfifo-fast-queue-disc", UNIT) +{ + AddTestCase (new PfifoFastQueueDiscTosPrioritization, TestCase::QUICK); + AddTestCase (new PfifoFastQueueDiscDscpPrioritization, TestCase::QUICK); + AddTestCase (new PfifoFastQueueDiscOverflow, TestCase::QUICK); + AddTestCase (new PfifoFastQueueDiscNonIpHeader, TestCase::QUICK); +} + +static PfifoFastQueueDiscTestSuite pfifoFastQueueTestSuite; diff --git a/src/traffic-control/wscript b/src/traffic-control/wscript new file mode 100644 index 00000000000..f6e5692295b --- /dev/null +++ b/src/traffic-control/wscript @@ -0,0 +1,38 @@ +# -*- 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', + 'model/queue-disc.cc', + 'model/pfifo-fast-queue-disc.cc', + 'helper/queue-disc-helper.cc', + 'helper/queue-disc-container.cc' + ] + + module_test = bld.create_ns3_module_test_library('traffic-control') + module_test.source = [ + 'test/pfifo-fast-queue-disc-test-suite.cc', + ] + + headers = bld(features='ns3header') + headers.module = 'traffic-control' + headers.source = [ + 'model/traffic-control-layer.h', + 'model/queue-disc.h', + 'model/pfifo-fast-queue-disc.h', + 'helper/queue-disc-helper.h', + 'helper/queue-disc-container.h' + ] + + if bld.env.ENABLE_EXAMPLES: + bld.recurse('examples') + + # bld.ns3_python_bindings() + diff --git a/src/wifi/model/regular-wifi-mac.cc b/src/wifi/model/regular-wifi-mac.cc index a028a62abb8..29d4e1a8b9f 100644 --- a/src/wifi/model/regular-wifi-mac.cc +++ b/src/wifi/model/regular-wifi-mac.cc @@ -439,6 +439,15 @@ RegularWifiMac::GetSsid (void) const return m_ssid; } +uint8_t +RegularWifiMac::GetTxQueuesN (void) const +{ + if (m_qosSupported) + return 4; + + return 1; +} + void RegularWifiMac::SetBssid (Mac48Address bssid) { diff --git a/src/wifi/model/regular-wifi-mac.h b/src/wifi/model/regular-wifi-mac.h index a1724e60163..18344b4c646 100644 --- a/src/wifi/model/regular-wifi-mac.h +++ b/src/wifi/model/regular-wifi-mac.h @@ -136,6 +136,10 @@ class RegularWifiMac : public WifiMac * \return the ssid which this MAC layer is going to try to stay in. */ virtual Ssid GetSsid (void) const; + /** + * \return the number of transmission queues handled by this MAC layer. + */ + virtual uint8_t GetTxQueuesN (void) const; /** * \param address the current address of this MAC layer. */ diff --git a/src/wifi/model/wifi-mac.h b/src/wifi/model/wifi-mac.h index 625847fd216..fc86fd6ec89 100644 --- a/src/wifi/model/wifi-mac.h +++ b/src/wifi/model/wifi-mac.h @@ -133,6 +133,10 @@ class WifiMac : public Object * \return the ssid which this MAC layer is going to try to stay in. */ virtual Ssid GetSsid (void) const = 0; + /** + * \return the number of transmission queues handled by this MAC layer. + */ + virtual uint8_t GetTxQueuesN (void) const = 0; /** * \param address the current address of this MAC layer. */ diff --git a/src/wifi/model/wifi-net-device.cc b/src/wifi/model/wifi-net-device.cc index ce083968731..a54afe9236b 100644 --- a/src/wifi/model/wifi-net-device.cc +++ b/src/wifi/model/wifi-net-device.cc @@ -131,6 +131,7 @@ void WifiNetDevice::SetMac (Ptr mac) { m_mac = mac; + SetTxQueuesN (m_mac->GetTxQueuesN ()); CompleteConfig (); }