app: E2E stats header
Right now, there is no way of extracting e2e statistics without using flow monitor. This patch enables, with an attribute, the possibility of adding a particular header to the outgoing packets, that will be read from PacketSink. The header contains Sequence, Size, and Timestamp, and therefore at the reception, it is possible to measure throughput and per-packet delay.
This commit is contained in:
@@ -73,6 +73,7 @@ allows to choose between Block Ack policy and Implicit Block Ack Request policy
|
||||
allows to request an acknowledgment after a configurable number of MPDUs have been
|
||||
transmitted.</li>
|
||||
<li>The MaxSize attribute is removed from the QueueBase base class and moved to subclasses. A new MaxSize attribute is therefore added to the DropTailQueue class, while the MaxQueueSize attribute of the WifiMacQueue class is renamed as MaxSize for API consistency.</li>
|
||||
<li>The applications have now a "EnableE2EStats" attribute.</li>
|
||||
</ul>
|
||||
<h2>Changes to existing API:</h2>
|
||||
<ul>
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "ns3/uinteger.h"
|
||||
#include "ns3/trace-source-accessor.h"
|
||||
#include "ns3/tcp-socket-factory.h"
|
||||
#include "ns3/boolean.h"
|
||||
#include "bulk-send-application.h"
|
||||
|
||||
namespace ns3 {
|
||||
@@ -52,6 +53,11 @@ BulkSendApplication::GetTypeId (void)
|
||||
AddressValue (),
|
||||
MakeAddressAccessor (&BulkSendApplication::m_peer),
|
||||
MakeAddressChecker ())
|
||||
.AddAttribute ("Local",
|
||||
"The Address on which to bind the socket. If not set, it is generated automatically.",
|
||||
AddressValue (),
|
||||
MakeAddressAccessor (&BulkSendApplication::m_local),
|
||||
MakeAddressChecker ())
|
||||
.AddAttribute ("MaxBytes",
|
||||
"The total number of bytes to send. "
|
||||
"Once these bytes are sent, "
|
||||
@@ -64,9 +70,17 @@ BulkSendApplication::GetTypeId (void)
|
||||
TypeIdValue (TcpSocketFactory::GetTypeId ()),
|
||||
MakeTypeIdAccessor (&BulkSendApplication::m_tid),
|
||||
MakeTypeIdChecker ())
|
||||
.AddAttribute ("EnableE2EStats",
|
||||
"Enable E2E statistics (sequences, timestamps)",
|
||||
BooleanValue (false),
|
||||
MakeBooleanAccessor (&BulkSendApplication::m_enableE2EStats),
|
||||
MakeBooleanChecker ())
|
||||
.AddTraceSource ("Tx", "A new packet is created and is sent",
|
||||
MakeTraceSourceAccessor (&BulkSendApplication::m_txTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource ("TxE2EStat", "Statistic sent with the packet",
|
||||
MakeTraceSourceAccessor (&BulkSendApplication::m_txTraceWithStats),
|
||||
"ns3::PacketSink::E2EStatCallback")
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
@@ -113,11 +127,13 @@ BulkSendApplication::DoDispose (void)
|
||||
void BulkSendApplication::StartApplication (void) // Called at time specified by Start
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
Address from;
|
||||
|
||||
// Create the socket if not already
|
||||
if (!m_socket)
|
||||
{
|
||||
m_socket = Socket::CreateSocket (GetNode (), m_tid);
|
||||
int ret = -1;
|
||||
|
||||
// Fatal error if socket type is not NS3_SOCK_STREAM or NS3_SOCK_SEQPACKET
|
||||
if (m_socket->GetSocketType () != Socket::NS3_SOCK_STREAM &&
|
||||
@@ -128,19 +144,28 @@ void BulkSendApplication::StartApplication (void) // Called at time specified by
|
||||
"In other words, use TCP instead of UDP.");
|
||||
}
|
||||
|
||||
if (Inet6SocketAddress::IsMatchingType (m_peer))
|
||||
if (! m_local.IsInvalid())
|
||||
{
|
||||
if (m_socket->Bind6 () == -1)
|
||||
NS_ABORT_MSG_IF ((Inet6SocketAddress::IsMatchingType (m_peer) && InetSocketAddress::IsMatchingType (m_local)) ||
|
||||
(InetSocketAddress::IsMatchingType (m_peer) && Inet6SocketAddress::IsMatchingType (m_local)),
|
||||
"Incompatible peer and local address IP version");
|
||||
ret = m_socket->Bind (m_local);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Inet6SocketAddress::IsMatchingType (m_peer))
|
||||
{
|
||||
NS_FATAL_ERROR ("Failed to bind socket");
|
||||
ret = m_socket->Bind6 ();
|
||||
}
|
||||
else if (InetSocketAddress::IsMatchingType (m_peer))
|
||||
{
|
||||
ret = m_socket->Bind ();
|
||||
}
|
||||
}
|
||||
else if (InetSocketAddress::IsMatchingType (m_peer))
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
if (m_socket->Bind () == -1)
|
||||
{
|
||||
NS_FATAL_ERROR ("Failed to bind socket");
|
||||
}
|
||||
NS_FATAL_ERROR ("Failed to bind socket");
|
||||
}
|
||||
|
||||
m_socket->Connect (m_peer);
|
||||
@@ -153,7 +178,8 @@ void BulkSendApplication::StartApplication (void) // Called at time specified by
|
||||
}
|
||||
if (m_connected)
|
||||
{
|
||||
SendData ();
|
||||
m_socket->GetSockName (from);
|
||||
SendData (from, m_peer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +201,7 @@ void BulkSendApplication::StopApplication (void) // Called at time specified by
|
||||
|
||||
// Private helpers
|
||||
|
||||
void BulkSendApplication::SendData (void)
|
||||
void BulkSendApplication::SendData (const Address &from, const Address &to)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
@@ -193,7 +219,24 @@ void BulkSendApplication::SendData (void)
|
||||
}
|
||||
|
||||
NS_LOG_LOGIC ("sending packet at " << Simulator::Now ());
|
||||
Ptr<Packet> packet = Create<Packet> (toSend);
|
||||
|
||||
Ptr<Packet> packet;
|
||||
if (m_enableE2EStats)
|
||||
{
|
||||
// Should we add a trace for the sent tx and timestamp?
|
||||
E2eStatsHeader header;
|
||||
header.SetSeq (m_seq++);
|
||||
header.SetSize (toSend);
|
||||
NS_ABORT_IF (toSend < header.GetSerializedSize ());
|
||||
packet = Create<Packet> (toSend - header.GetSerializedSize ());
|
||||
packet->AddHeader (header);
|
||||
m_txTraceWithStats (packet, from, to, header);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet = Create<Packet> (toSend);
|
||||
}
|
||||
|
||||
int actual = m_socket->Send (packet);
|
||||
if (actual > 0)
|
||||
{
|
||||
@@ -221,7 +264,10 @@ void BulkSendApplication::ConnectionSucceeded (Ptr<Socket> socket)
|
||||
NS_LOG_FUNCTION (this << socket);
|
||||
NS_LOG_LOGIC ("BulkSendApplication Connection succeeded");
|
||||
m_connected = true;
|
||||
SendData ();
|
||||
Address from, to;
|
||||
socket->GetSockName (from);
|
||||
socket->GetPeerName (to);
|
||||
SendData (from, to);
|
||||
}
|
||||
|
||||
void BulkSendApplication::ConnectionFailed (Ptr<Socket> socket)
|
||||
@@ -230,13 +276,16 @@ void BulkSendApplication::ConnectionFailed (Ptr<Socket> socket)
|
||||
NS_LOG_LOGIC ("BulkSendApplication, Connection Failed");
|
||||
}
|
||||
|
||||
void BulkSendApplication::DataSend (Ptr<Socket>, uint32_t)
|
||||
void BulkSendApplication::DataSend (Ptr<Socket> socket, uint32_t)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
if (m_connected)
|
||||
{ // Only send new data if the connection has completed
|
||||
SendData ();
|
||||
Address from, to;
|
||||
socket->GetSockName (from);
|
||||
socket->GetPeerName (to);
|
||||
SendData (from, to);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "ns3/event-id.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/traced-callback.h"
|
||||
#include "ns3/e2e-stats-header.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -64,6 +65,12 @@ class Socket;
|
||||
* For example, TCP sockets can be used, but
|
||||
* UDP sockets can not be used.
|
||||
*
|
||||
* If the attribute "EnableE2EStats" is enabled, the application will use
|
||||
* some byte of the payload to store an header with a sequence number,
|
||||
* a timestamp, and the size of the packet sent. To get these statistics,
|
||||
* please use PacketSink (and enable its "EnableE2EStats" attribute) or extract
|
||||
* the header yourself in your application (you can see how PacketSink is working
|
||||
* with such headers).
|
||||
*/
|
||||
class BulkSendApplication : public Application
|
||||
{
|
||||
@@ -108,20 +115,29 @@ private:
|
||||
|
||||
/**
|
||||
* \brief Send data until the L4 transmission buffer is full.
|
||||
* \param from From address
|
||||
* \param to To address
|
||||
*/
|
||||
void SendData ();
|
||||
void SendData (const Address &from, const Address &to);
|
||||
|
||||
Ptr<Socket> m_socket; //!< Associated socket
|
||||
Address m_peer; //!< Peer address
|
||||
Address m_local; //!< Local address to bind to
|
||||
bool m_connected; //!< True if connected
|
||||
uint32_t m_sendSize; //!< Size of data to send each time
|
||||
uint64_t m_maxBytes; //!< Limit total number of bytes sent
|
||||
uint64_t m_totBytes; //!< Total bytes sent so far
|
||||
TypeId m_tid; //!< The type of protocol to use.
|
||||
uint32_t m_seq {0}; //!< Sequence
|
||||
bool m_enableE2EStats {false}; //!< Enable or disable the e2e statistic generation
|
||||
|
||||
|
||||
/// Traced Callback: sent packets
|
||||
TracedCallback<Ptr<const Packet> > m_txTrace;
|
||||
|
||||
/// Callback for tracing the packet Tx events, includes source, destination, and the packet sent
|
||||
TracedCallback<Ptr<const Packet>, const Address &, const Address &, const E2eStatsHeader &> m_txTraceWithStats;
|
||||
|
||||
private:
|
||||
/**
|
||||
* \brief Connection Succeeded (called by Socket through a callback)
|
||||
|
||||
86
src/applications/model/e2e-stats-header.cc
Normal file
86
src/applications/model/e2e-stats-header.cc
Normal file
@@ -0,0 +1,86 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2018 Natale Patriciello <natale.patriciello@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "e2e-stats-header.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("SizeHeader");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (E2eStatsHeader);
|
||||
|
||||
E2eStatsHeader::E2eStatsHeader ()
|
||||
: SeqTsHeader ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
TypeId
|
||||
E2eStatsHeader::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::SizeHeader")
|
||||
.SetParent<SeqTsHeader> ()
|
||||
.SetGroupName ("Applications")
|
||||
.AddConstructor<E2eStatsHeader> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
TypeId
|
||||
E2eStatsHeader::GetInstanceTypeId (void) const
|
||||
{
|
||||
return GetTypeId ();
|
||||
}
|
||||
|
||||
void
|
||||
E2eStatsHeader::Print (std::ostream &os) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this << &os);
|
||||
os << "(size=" << m_size << ") AND ";
|
||||
SeqTsHeader::Print (os);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
E2eStatsHeader::GetSerializedSize (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return SeqTsHeader::GetSerializedSize () + 8;
|
||||
}
|
||||
|
||||
void
|
||||
E2eStatsHeader::Serialize (Buffer::Iterator start) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this << &start);
|
||||
Buffer::Iterator i = start;
|
||||
i.WriteHtonU64 (m_size);
|
||||
SeqTsHeader::Serialize (i);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
E2eStatsHeader::Deserialize (Buffer::Iterator start)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << &start);
|
||||
Buffer::Iterator i = start;
|
||||
m_size = i.ReadNtohU64 ();
|
||||
SeqTsHeader::Deserialize (i);
|
||||
return GetSerializedSize ();
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
89
src/applications/model/e2e-stats-header.h
Normal file
89
src/applications/model/e2e-stats-header.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2018 Natale Patriciello <natale.patriciello@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ns3/seq-ts-header.h>
|
||||
|
||||
namespace ns3 {
|
||||
/**
|
||||
* \ingroup applications
|
||||
* \brief Header with a sequence, a timestamp, and a "size" attribute
|
||||
*
|
||||
* Sometimes, you would need an header that not only track an application
|
||||
* sequence number, or an application timestamp, but also track
|
||||
* how big are these application packets.
|
||||
*
|
||||
* This header extends SeqTsHeader, adding space to store the information
|
||||
* about the size of these packets.
|
||||
*
|
||||
* When you will use a protocol like TCP, you will find the answer to the question
|
||||
* "isn't SeqTsHeader enough?".
|
||||
*/
|
||||
class E2eStatsHeader : public SeqTsHeader
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
|
||||
/**
|
||||
* @brief SizeHeader constructor
|
||||
*/
|
||||
E2eStatsHeader ();
|
||||
|
||||
/**
|
||||
* \brief ~SizeHeader
|
||||
*
|
||||
* Nothing much to add here
|
||||
*/
|
||||
virtual ~E2eStatsHeader () override
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the size information that the header will carry
|
||||
* @param size the size
|
||||
*/
|
||||
void SetSize (uint64_t size)
|
||||
{
|
||||
m_size = size;
|
||||
}
|
||||
/**
|
||||
* @brief Get the size information that the header is carrying
|
||||
* @return the size
|
||||
*/
|
||||
uint64_t GetSize (void) const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
// Inherited
|
||||
virtual TypeId GetInstanceTypeId (void) const override;
|
||||
virtual void Print (std::ostream &os) const override;
|
||||
virtual uint32_t GetSerializedSize (void) const override;
|
||||
virtual void Serialize (Buffer::Iterator start) const override;
|
||||
virtual uint32_t Deserialize (Buffer::Iterator start) override;
|
||||
|
||||
private:
|
||||
uint64_t m_size {0}; //!< The 'size' information that the header is carrying
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "ns3/udp-socket-factory.h"
|
||||
#include "ns3/string.h"
|
||||
#include "ns3/pointer.h"
|
||||
#include "ns3/boolean.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -67,6 +68,11 @@ OnOffApplication::GetTypeId (void)
|
||||
AddressValue (),
|
||||
MakeAddressAccessor (&OnOffApplication::m_peer),
|
||||
MakeAddressChecker ())
|
||||
.AddAttribute ("Local",
|
||||
"The Address on which to bind the socket. If not set, it is generated automatically.",
|
||||
AddressValue (),
|
||||
MakeAddressAccessor (&OnOffApplication::m_local),
|
||||
MakeAddressChecker ())
|
||||
.AddAttribute ("OnTime", "A RandomVariableStream used to pick the duration of the 'On' state.",
|
||||
StringValue ("ns3::ConstantRandomVariable[Constant=1.0]"),
|
||||
MakePointerAccessor (&OnOffApplication::m_onTime),
|
||||
@@ -88,12 +94,20 @@ OnOffApplication::GetTypeId (void)
|
||||
MakeTypeIdAccessor (&OnOffApplication::m_tid),
|
||||
// This should check for SocketFactory as a parent
|
||||
MakeTypeIdChecker ())
|
||||
.AddAttribute ("EnableE2EStats",
|
||||
"Enable E2E statistics (sequences, timestamps)",
|
||||
BooleanValue (false),
|
||||
MakeBooleanAccessor (&OnOffApplication::m_enableE2EStats),
|
||||
MakeBooleanChecker ())
|
||||
.AddTraceSource ("Tx", "A new packet is created and is sent",
|
||||
MakeTraceSourceAccessor (&OnOffApplication::m_txTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource ("TxWithAddresses", "A new packet is created and is sent",
|
||||
MakeTraceSourceAccessor (&OnOffApplication::m_txTraceWithAddresses),
|
||||
"ns3::Packet::TwoAddressTracedCallback")
|
||||
.AddTraceSource ("TxE2EStat", "Statistic sent with the packet",
|
||||
MakeTraceSourceAccessor (&OnOffApplication::m_txTraceWithStats),
|
||||
"ns3::PacketSink::E2EStatCallback")
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
@@ -157,21 +171,33 @@ void OnOffApplication::StartApplication () // Called at time specified by Start
|
||||
if (!m_socket)
|
||||
{
|
||||
m_socket = Socket::CreateSocket (GetNode (), m_tid);
|
||||
if (Inet6SocketAddress::IsMatchingType (m_peer))
|
||||
int ret = -1;
|
||||
|
||||
if (! m_local.IsInvalid())
|
||||
{
|
||||
if (m_socket->Bind6 () == -1)
|
||||
NS_ABORT_MSG_IF ((Inet6SocketAddress::IsMatchingType (m_peer) && InetSocketAddress::IsMatchingType (m_local)) ||
|
||||
(InetSocketAddress::IsMatchingType (m_peer) && Inet6SocketAddress::IsMatchingType (m_local)),
|
||||
"Incompatible peer and local address IP version");
|
||||
ret = m_socket->Bind (m_local);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Inet6SocketAddress::IsMatchingType (m_peer))
|
||||
{
|
||||
NS_FATAL_ERROR ("Failed to bind socket");
|
||||
ret = m_socket->Bind6 ();
|
||||
}
|
||||
else if (InetSocketAddress::IsMatchingType (m_peer) ||
|
||||
PacketSocketAddress::IsMatchingType (m_peer))
|
||||
{
|
||||
ret = m_socket->Bind ();
|
||||
}
|
||||
}
|
||||
else if (InetSocketAddress::IsMatchingType (m_peer) ||
|
||||
PacketSocketAddress::IsMatchingType (m_peer))
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
if (m_socket->Bind () == -1)
|
||||
{
|
||||
NS_FATAL_ERROR ("Failed to bind socket");
|
||||
}
|
||||
NS_FATAL_ERROR ("Failed to bind socket");
|
||||
}
|
||||
|
||||
m_socket->Connect (m_peer);
|
||||
m_socket->SetAllowBroadcast (true);
|
||||
m_socket->ShutdownRecv ();
|
||||
@@ -283,7 +309,26 @@ void OnOffApplication::SendPacket ()
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
NS_ASSERT (m_sendEvent.IsExpired ());
|
||||
Ptr<Packet> packet = Create<Packet> (m_pktSize);
|
||||
|
||||
Ptr<Packet> packet;
|
||||
if (m_enableE2EStats)
|
||||
{
|
||||
Address from, to;
|
||||
m_socket->GetSockName (from);
|
||||
m_socket->GetPeerName (to);
|
||||
E2eStatsHeader header;
|
||||
header.SetSeq (m_seq++);
|
||||
header.SetSize (m_pktSize);
|
||||
NS_ABORT_IF (m_pktSize < header.GetSerializedSize ());
|
||||
packet = Create<Packet> (m_pktSize - header.GetSerializedSize ());
|
||||
packet->AddHeader (header);
|
||||
m_txTraceWithStats (packet, from, to, header);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet = Create<Packet> (m_pktSize);
|
||||
}
|
||||
|
||||
m_txTrace (packet);
|
||||
m_socket->Send (packet);
|
||||
m_totBytes += m_pktSize;
|
||||
@@ -324,6 +369,7 @@ void OnOffApplication::ConnectionSucceeded (Ptr<Socket> socket)
|
||||
void OnOffApplication::ConnectionFailed (Ptr<Socket> socket)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << socket);
|
||||
NS_FATAL_ERROR ("Can't connect");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/data-rate.h"
|
||||
#include "ns3/traced-callback.h"
|
||||
#include "ns3/e2e-stats-header.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -82,6 +83,13 @@ class Socket;
|
||||
*
|
||||
* If the underlying socket type supports broadcast, this application
|
||||
* will automatically enable the SetAllowBroadcast(true) socket option.
|
||||
*
|
||||
* If the attribute "EnableE2EStats" is enabled, the application will use
|
||||
* some byte of the payload to store an header with a sequence number,
|
||||
* a timestamp, and the size of the packet sent. To get these statistics,
|
||||
* please use PacketSink (and enable its "EnableE2EStats" attribute) or extract
|
||||
* the header yourself in your application (you can see how PacketSink is working
|
||||
* with such headers).
|
||||
*/
|
||||
class OnOffApplication : public Application
|
||||
{
|
||||
@@ -150,6 +158,7 @@ private:
|
||||
|
||||
Ptr<Socket> m_socket; //!< Associated socket
|
||||
Address m_peer; //!< Peer address
|
||||
Address m_local; //!< Local address to bind to
|
||||
bool m_connected; //!< True if connected
|
||||
Ptr<RandomVariableStream> m_onTime; //!< rng for On Time
|
||||
Ptr<RandomVariableStream> m_offTime; //!< rng for Off Time
|
||||
@@ -163,6 +172,9 @@ private:
|
||||
EventId m_startStopEvent; //!< Event id for next start or stop event
|
||||
EventId m_sendEvent; //!< Event id of pending "send packet" event
|
||||
TypeId m_tid; //!< Type of the socket used
|
||||
uint32_t m_seq {0}; //!< Sequence
|
||||
bool m_enableE2EStats {false}; //!< Enable or disable the e2e statistic generation
|
||||
|
||||
|
||||
/// Traced Callback: transmitted packets.
|
||||
TracedCallback<Ptr<const Packet> > m_txTrace;
|
||||
@@ -170,6 +182,9 @@ private:
|
||||
/// Callbacks for tracing the packet Tx events, includes source and destination addresses
|
||||
TracedCallback<Ptr<const Packet>, const Address &, const Address &> m_txTraceWithAddresses;
|
||||
|
||||
/// Callback for tracing the packet Tx events, includes source, destination, and the packet sent
|
||||
TracedCallback<Ptr<const Packet>, const Address &, const Address &, const E2eStatsHeader &> m_txTraceWithStats;
|
||||
|
||||
private:
|
||||
/**
|
||||
* \brief Schedule the next packet transmission
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "ns3/trace-source-accessor.h"
|
||||
#include "ns3/udp-socket-factory.h"
|
||||
#include "packet-sink.h"
|
||||
#include "ns3/boolean.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -55,6 +56,11 @@ PacketSink::GetTypeId (void)
|
||||
TypeIdValue (UdpSocketFactory::GetTypeId ()),
|
||||
MakeTypeIdAccessor (&PacketSink::m_tid),
|
||||
MakeTypeIdChecker ())
|
||||
.AddAttribute ("EnableE2EStats",
|
||||
"Enable E2E statistics (sequences, timestamps)",
|
||||
BooleanValue (false),
|
||||
MakeBooleanAccessor (&PacketSink::m_enableE2EStats),
|
||||
MakeBooleanChecker ())
|
||||
.AddTraceSource ("Rx",
|
||||
"A packet has been received",
|
||||
MakeTraceSourceAccessor (&PacketSink::m_rxTrace),
|
||||
@@ -62,6 +68,10 @@ PacketSink::GetTypeId (void)
|
||||
.AddTraceSource ("RxWithAddresses", "A packet has been received",
|
||||
MakeTraceSourceAccessor (&PacketSink::m_rxTraceWithAddresses),
|
||||
"ns3::Packet::TwoAddressTracedCallback")
|
||||
.AddTraceSource ("RxE2EStat",
|
||||
"A sequence number and a timestamp have been received",
|
||||
MakeTraceSourceAccessor (&PacketSink::m_rxTraceWithAddressesAndSeqTs),
|
||||
"ns3::PacketSink::E2EStatCallback")
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
@@ -197,6 +207,50 @@ void PacketSink::HandleRead (Ptr<Socket> socket)
|
||||
socket->GetSockName (localAddress);
|
||||
m_rxTrace (packet, from);
|
||||
m_rxTraceWithAddresses (packet, from, localAddress);
|
||||
|
||||
if (m_enableE2EStats)
|
||||
{
|
||||
PacketReceived (packet, from, localAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PacketSink::PacketReceived (const Ptr<Packet> &p, const Address &from,
|
||||
const Address &localAddress)
|
||||
{
|
||||
E2eStatsHeader header;
|
||||
Ptr<Packet> buffer;
|
||||
|
||||
auto itBuffer = m_buffer.find (from);
|
||||
if (itBuffer == m_buffer.end ())
|
||||
{
|
||||
itBuffer = m_buffer.insert (std::make_pair (from, Create<Packet> (0))).first;
|
||||
}
|
||||
|
||||
buffer = itBuffer->second;
|
||||
buffer->AddAtEnd (p);
|
||||
buffer->PeekHeader (header);
|
||||
|
||||
NS_ABORT_IF (header.GetSize () == 0);
|
||||
|
||||
while (buffer->GetSize () >= header.GetSize ())
|
||||
{
|
||||
Ptr<Packet> complete = buffer->CreateFragment (0, static_cast<uint32_t> (header.GetSize ()));
|
||||
buffer->RemoveAtStart (static_cast<uint32_t> (header.GetSize ()));
|
||||
|
||||
complete->RemoveHeader (header);
|
||||
|
||||
m_rxTraceWithAddressesAndSeqTs (complete, from, localAddress, header);
|
||||
|
||||
if (buffer->GetSize () > 0)
|
||||
{
|
||||
buffer->PeekHeader (header);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/traced-callback.h"
|
||||
#include "ns3/address.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/e2e-stats-header.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -91,7 +94,19 @@ public:
|
||||
* \return list of pointers to accepted sockets
|
||||
*/
|
||||
std::list<Ptr<Socket> > GetAcceptedSockets (void) const;
|
||||
|
||||
|
||||
/**
|
||||
* TracedCallback signature for an E2E stat callback
|
||||
*
|
||||
* \param p The packet received
|
||||
* \param from From address
|
||||
* \param to Local address
|
||||
* \param seq The sequence received
|
||||
* \param time The delay the sequence has needed from the sender to the receiver
|
||||
*/
|
||||
typedef void (* E2EStatCallback)(Ptr<const Packet> p, const Address &from, const Address & to,
|
||||
const E2eStatsHeader &header);
|
||||
|
||||
protected:
|
||||
virtual void DoDispose (void);
|
||||
private:
|
||||
@@ -121,7 +136,44 @@ private:
|
||||
*/
|
||||
void HandlePeerError (Ptr<Socket> socket);
|
||||
|
||||
// In the case of TCP, each socket accept returns a new socket, so the
|
||||
/**
|
||||
* \brief Packet received: calculation of the e2e statistics
|
||||
* \param p received packet
|
||||
* \param from from address
|
||||
* \param localAddress local address
|
||||
*
|
||||
* The method calculates e2e statistics about the received packet. If
|
||||
* the transport protocol is stream-based, then reconstruct first the
|
||||
* original packet, and then extract the statistic header from it.
|
||||
*/
|
||||
void PacketReceived (const Ptr<Packet> &p, const Address &from, const Address &localAddress);
|
||||
|
||||
/**
|
||||
* \brief Hashing for the Address class
|
||||
*/
|
||||
struct AddressHash
|
||||
{
|
||||
/**
|
||||
* \brief operator ()
|
||||
* \param x the address of which calculate the hash
|
||||
* \return the hash of x
|
||||
*
|
||||
* Should this method go in address.h?
|
||||
*
|
||||
* It calculates the hash taking the uint32_t hash value of the ipv4 address.
|
||||
* It works only for InetSocketAddresses (Ipv4 version)
|
||||
*/
|
||||
size_t operator() (const Address &x) const
|
||||
{
|
||||
NS_ABORT_IF (!InetSocketAddress::IsMatchingType (x));
|
||||
InetSocketAddress a = InetSocketAddress::ConvertFrom (x);
|
||||
return std::hash<uint32_t>()(a.GetIpv4 ().Get ());
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_map<Address, Ptr<Packet>, AddressHash> m_buffer; //!< Buffer for received packets
|
||||
|
||||
// In the case of TCP, each socket accept returns a new socket, so the
|
||||
// listening socket is stored separately from the accepted sockets
|
||||
Ptr<Socket> m_socket; //!< Listening socket
|
||||
std::list<Ptr<Socket> > m_socketList; //!< the accepted sockets
|
||||
@@ -130,12 +182,14 @@ private:
|
||||
uint64_t m_totalRx; //!< Total bytes received
|
||||
TypeId m_tid; //!< Protocol TypeId
|
||||
|
||||
bool m_enableE2EStats {false}; //!< Enable or disable the E2E statistics generation
|
||||
|
||||
/// Traced Callback: received packets, source address.
|
||||
TracedCallback<Ptr<const Packet>, const Address &> m_rxTrace;
|
||||
|
||||
/// Callback for tracing the packet Rx events, includes source and destination addresses
|
||||
TracedCallback<Ptr<const Packet>, const Address &, const Address &> m_rxTraceWithAddresses;
|
||||
|
||||
/// Callback for tracing the packet Rx events, includes source, destination addresses, sequence and timestamp
|
||||
TracedCallback<Ptr<const Packet>, const Address &, const Address &, const E2eStatsHeader&> m_rxTraceWithAddressesAndSeqTs;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -31,7 +31,8 @@ namespace ns3 {
|
||||
* \brief Packet header for UDP client/server application.
|
||||
*
|
||||
* The header is made of a 32bits sequence number followed by
|
||||
* a 64bits time stamp.
|
||||
* a 64bits time stamp. If you need to use this header with a transport protocol
|
||||
* such as TCP, please consider to use SizeHeader.
|
||||
*/
|
||||
class SeqTsHeader : public Header
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@ def build(bld):
|
||||
'model/udp-client.cc',
|
||||
'model/udp-server.cc',
|
||||
'model/seq-ts-header.cc',
|
||||
'model/e2e-stats-header.cc',
|
||||
'model/udp-trace-client.cc',
|
||||
'model/packet-loss-counter.cc',
|
||||
'model/udp-echo-client.cc',
|
||||
@@ -41,6 +42,7 @@ def build(bld):
|
||||
'model/udp-client.h',
|
||||
'model/udp-server.h',
|
||||
'model/seq-ts-header.h',
|
||||
'model/e2e-stats-header.h',
|
||||
'model/udp-trace-client.h',
|
||||
'model/packet-loss-counter.h',
|
||||
'model/udp-echo-client.h',
|
||||
|
||||
Reference in New Issue
Block a user