merge with head
This commit is contained in:
1
.hgtags
1
.hgtags
@@ -1,3 +1,4 @@
|
||||
56928998e05c9c11f5f3aefe79be8d2843e0db88 release ns-3.0.1
|
||||
7ac5a4b0969b255c4824c926c2b37ef450136ce9 release ns-3.0.2
|
||||
0dc81e76166c56aaae64da48b673b62155943aad packet-history-working
|
||||
38099dd26e9467b8f49f8632f22789858149a6e7 release ns-3.0.3
|
||||
|
||||
19
SConstruct
19
SConstruct
@@ -187,6 +187,8 @@ common.add_sources([
|
||||
'chunk.cc',
|
||||
'header.cc',
|
||||
'trailer.cc',
|
||||
'packet-printer.cc',
|
||||
'packet-metadata.cc',
|
||||
'packet.cc',
|
||||
'tags.cc',
|
||||
'pcap-writer.cc',
|
||||
@@ -208,6 +210,8 @@ common.add_inst_headers([
|
||||
'trailer.h',
|
||||
'tags.h',
|
||||
'packet.h',
|
||||
'packet-printer.h',
|
||||
'packet-metadata.h',
|
||||
'uv-trace-source.h',
|
||||
'sv-trace-source.h',
|
||||
'fv-trace-source.h',
|
||||
@@ -303,8 +307,6 @@ inode.add_sources ([
|
||||
'udp-impl.cc',
|
||||
])
|
||||
inode.add_headers ([
|
||||
'ipv4-header.h',
|
||||
'udp-header.h',
|
||||
'ipv4-checksum.h',
|
||||
'arp-header.h',
|
||||
'arp-cache.h',
|
||||
@@ -334,6 +336,8 @@ inode.add_inst_headers ([
|
||||
'internet-node.h',
|
||||
'ascii-trace.h',
|
||||
'pcap-trace.h',
|
||||
'ipv4-header.h',
|
||||
'udp-header.h',
|
||||
])
|
||||
|
||||
|
||||
@@ -367,9 +371,9 @@ bench_object.add_deps(['core'])
|
||||
bench_object.add_source('bench-object.cc')
|
||||
|
||||
bench_packets = build.Ns3Module('bench-packets', 'utils')
|
||||
#ns3.add(bench_packets)
|
||||
ns3.add(bench_packets)
|
||||
bench_packets.set_executable()
|
||||
bench_packets.add_dep('core')
|
||||
bench_packets.add_deps (['core', 'common'])
|
||||
bench_packets.add_source('bench-packets.cc')
|
||||
|
||||
bench_simu = build.Ns3Module('bench-simulator', 'utils')
|
||||
@@ -393,6 +397,13 @@ sample_debug.add_dep('core')
|
||||
sample_debug.add_source('main-debug.cc')
|
||||
sample_debug.add_source('main-debug-other.cc')
|
||||
|
||||
sample_packet_printer = build.Ns3Module('sample-packet-printer', 'samples')
|
||||
sample_packet_printer.set_executable()
|
||||
ns3.add(sample_packet_printer)
|
||||
sample_packet_printer.add_deps (['common', 'internet-node'])
|
||||
sample_packet_printer.add_source('main-packet-printer.cc')
|
||||
|
||||
|
||||
sample_callback = build.Ns3Module('sample-callback', 'samples')
|
||||
sample_callback.set_executable()
|
||||
ns3.add(sample_callback)
|
||||
|
||||
149
samples/main-packet-printer.cc
Normal file
149
samples/main-packet-printer.cc
Normal file
@@ -0,0 +1,149 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/header.h"
|
||||
#include "ns3/packet-printer.h"
|
||||
#include "ns3/ipv4-header.h"
|
||||
#include "ns3/udp-header.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
|
||||
void DefaultPrint (void)
|
||||
{
|
||||
// We create a packet with 1000 bytes of zero payload
|
||||
// and add 3 headers to this packet.
|
||||
Packet p (1000);
|
||||
Ipv4Header ipv4;
|
||||
UdpHeader udp;
|
||||
ipv4.SetSource (Ipv4Address ("192.168.0.1"));
|
||||
ipv4.SetDestination (Ipv4Address ("192.168.0.2"));
|
||||
udp.SetSource (1025);
|
||||
udp.SetDestination (80);
|
||||
p.AddHeader (udp);
|
||||
p.AddHeader (ipv4);
|
||||
|
||||
std::cout << "full packet size=" << p.GetSize () << std::endl;
|
||||
p.Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
|
||||
// Now, we fragment our packet in 3 consecutive pieces.
|
||||
Packet p1 = p.CreateFragment (0, 2);
|
||||
Packet p2 = p.CreateFragment (2, 1000);
|
||||
Packet p3 = p.CreateFragment (1002, 26);
|
||||
|
||||
std::cout << "fragment1" << std::endl;
|
||||
p1.Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
std::cout << "fragment2" << std::endl;
|
||||
p2.Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
std::cout << "fragment3" << std::endl;
|
||||
p3.Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
// And, finally, we re-aggregate the 3 consecutive pieces.
|
||||
Packet aggregate = p1;
|
||||
aggregate.AddAtEnd (p2);
|
||||
aggregate.AddAtEnd (p3);
|
||||
std::cout << "aggregated" << std::endl;
|
||||
aggregate.Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
void
|
||||
DoPrintDefault (std::ostream &os,uint32_t packetUid, uint32_t size,
|
||||
std::string &name, struct PacketPrinter::FragmentInformation info)
|
||||
{
|
||||
os << name <<" (size " << size << " trim_start " << info.start << " trim_end " << info.end << ")";
|
||||
}
|
||||
void
|
||||
DoPrintPayload (std::ostream & os,uint32_t packetUid,uint32_t size,
|
||||
struct PacketPrinter::FragmentInformation info)
|
||||
{
|
||||
os << "PAYLOAD (size " << size << " trim_start " << info.start << " trim_end " << info.end << ")";
|
||||
}
|
||||
void
|
||||
DoPrintIpv4Header (std::ostream &os, uint32_t packetUid, uint32_t size, const Ipv4Header *ipv4)
|
||||
{
|
||||
os << "IPV4 " << ipv4->GetSource () << " > " << ipv4->GetDestination ();
|
||||
}
|
||||
void
|
||||
DoPrintIpv4HeaderFragment (std::ostream &os, uint32_t packetUid, uint32_t size,
|
||||
std::string &name, struct PacketPrinter::FragmentInformation info)
|
||||
{
|
||||
os << "IPV4 fragment";
|
||||
}
|
||||
|
||||
void NonDefaultPrint (void)
|
||||
{
|
||||
// create an adhoc packet printer.
|
||||
PacketPrinter printer;
|
||||
// print from first header to last trailer
|
||||
printer.PrintForward ();
|
||||
// set a string separator automatically inserted
|
||||
// between each call to a printing function.
|
||||
printer.SetSeparator (" - ");
|
||||
// set the default print function: invoked if no
|
||||
// specialized function has been provided for a header
|
||||
// or trailer
|
||||
printer.AddDefaultPrinter (MakeCallback (&DoPrintDefault));
|
||||
// set the payload print function
|
||||
printer.AddPayloadPrinter (MakeCallback (&DoPrintPayload));
|
||||
// set the print function for the header type Ipv4Header.
|
||||
printer.AddHeaderPrinter (MakeCallback (&DoPrintIpv4Header),
|
||||
MakeCallback (&DoPrintIpv4HeaderFragment));
|
||||
|
||||
|
||||
// We create a packet with 1000 bytes of zero payload
|
||||
Packet p (1000);
|
||||
Ipv4Header ipv4;
|
||||
UdpHeader udp;
|
||||
ipv4.SetSource (Ipv4Address ("192.168.0.1"));
|
||||
ipv4.SetDestination (Ipv4Address ("192.168.0.2"));
|
||||
udp.SetSource (1025);
|
||||
udp.SetDestination (80);
|
||||
p.AddHeader (udp);
|
||||
p.AddHeader (ipv4);
|
||||
|
||||
std::cout << "full packet size=" << p.GetSize () << std::endl;
|
||||
p.Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
|
||||
|
||||
// fragment our packet in 3 pieces
|
||||
Packet p1 = p.CreateFragment (0, 2);
|
||||
Packet p2 = p.CreateFragment (2, 1000);
|
||||
Packet p3 = p.CreateFragment (1002, 26);
|
||||
std::cout << "fragment1" << std::endl;
|
||||
p1.Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
std::cout << "fragment2" << std::endl;
|
||||
p2.Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
std::cout << "fragment3" << std::endl;
|
||||
p3.Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
|
||||
// aggregate all 3 fragments of the original packet
|
||||
// to reconstruct a copy of the original packet.
|
||||
Packet aggregate = p1;
|
||||
aggregate.AddAtEnd (p2);
|
||||
aggregate.AddAtEnd (p3);
|
||||
std::cout << "aggregated" << std::endl;
|
||||
aggregate.Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
Packet::EnableMetadata ();
|
||||
|
||||
DefaultPrint ();
|
||||
|
||||
NonDefaultPrint ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -15,6 +15,7 @@ public:
|
||||
void SetData (uint16_t data);
|
||||
uint16_t GetData (void) const;
|
||||
private:
|
||||
virtual std::string DoGetName (void) const;
|
||||
virtual void PrintTo (std::ostream &os) const;
|
||||
virtual void SerializeTo (Buffer::Iterator start) const;
|
||||
virtual uint32_t DeserializeFrom (Buffer::Iterator start);
|
||||
@@ -27,6 +28,11 @@ MyHeader::MyHeader ()
|
||||
{}
|
||||
MyHeader::~MyHeader ()
|
||||
{}
|
||||
std::string
|
||||
MyHeader::DoGetName (void) const
|
||||
{
|
||||
return "MyHeader";
|
||||
}
|
||||
void
|
||||
MyHeader::PrintTo (std::ostream &os) const
|
||||
{
|
||||
|
||||
@@ -224,7 +224,7 @@ Buffer::AddAtEnd (uint32_t end)
|
||||
uint32_t newSize = m_size + end;
|
||||
struct Buffer::BufferData *newData = Buffer::Allocate (newSize, 0);
|
||||
memcpy (newData->m_data, GetStart (), m_size);
|
||||
newData->m_initialStart = m_data->m_initialStart;
|
||||
newData->m_initialStart = m_data->m_initialStart - m_start;
|
||||
m_data->m_count--;
|
||||
if (m_data->m_count == 0)
|
||||
{
|
||||
@@ -663,6 +663,12 @@ BufferTest::RunTests (void)
|
||||
i.Prev (4);
|
||||
i.WriteU8 (1, 4);
|
||||
|
||||
buffer = Buffer (1);
|
||||
buffer.AddAtEnd (100);
|
||||
i = buffer.End ();
|
||||
i.Prev (100);
|
||||
i.WriteU8 (1, 100);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -320,6 +320,8 @@ public:
|
||||
*/
|
||||
inline Buffer::Iterator End (void) const;
|
||||
|
||||
void TransformIntoRealBuffer (void) const;
|
||||
|
||||
inline Buffer (Buffer const &o);
|
||||
inline Buffer &operator = (Buffer const &o);
|
||||
inline Buffer ();
|
||||
@@ -337,7 +339,6 @@ private:
|
||||
typedef std::vector<struct Buffer::BufferData*> BufferDataList;
|
||||
|
||||
inline uint8_t *GetStart (void) const;
|
||||
void TransformIntoRealBuffer (void) const;
|
||||
static void Recycle (struct Buffer::BufferData *data);
|
||||
static struct Buffer::BufferData *Create (void);
|
||||
static struct Buffer::BufferData *Allocate (uint32_t size, uint32_t start);
|
||||
@@ -543,6 +544,8 @@ Buffer::Iterator::Write (Iterator start, Iterator end)
|
||||
{
|
||||
NS_ASSERT (start.m_data == end.m_data);
|
||||
NS_ASSERT (start.m_current <= end.m_current);
|
||||
NS_ASSERT (start.m_zeroStart == end.m_zeroStart);
|
||||
NS_ASSERT (start.m_zeroEnd == end.m_zeroEnd);
|
||||
NS_ASSERT (m_data != start.m_data);
|
||||
uint32_t size = end.m_current - start.m_current;
|
||||
uint8_t *src = start.m_data + start.GetIndex (size);
|
||||
|
||||
@@ -30,6 +30,11 @@ Chunk::Chunk ()
|
||||
Chunk::~Chunk ()
|
||||
{}
|
||||
|
||||
std::string
|
||||
Chunk::GetName (void) const
|
||||
{
|
||||
return DoGetName ();
|
||||
}
|
||||
void
|
||||
Chunk::Print (std::ostream &os) const
|
||||
{
|
||||
|
||||
@@ -33,11 +33,13 @@ public:
|
||||
Chunk ();
|
||||
virtual ~Chunk ();
|
||||
|
||||
std::string GetName (void) const;
|
||||
void Print (std::ostream &os) const;
|
||||
uint32_t GetSize (void) const;
|
||||
void Serialize (Buffer::Iterator start) const;
|
||||
uint32_t Deserialize (Buffer::Iterator start);
|
||||
private:
|
||||
virtual std::string DoGetName (void) const = 0;
|
||||
virtual void PrintTo (std::ostream &os) const = 0;
|
||||
virtual uint32_t GetSerializedSize (void) const = 0;
|
||||
virtual void SerializeTo (Buffer::Iterator i) const = 0;
|
||||
|
||||
@@ -23,9 +23,8 @@
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/fatal-error.h"
|
||||
|
||||
namespace {
|
||||
|
||||
bool
|
||||
static bool
|
||||
DoParse (const std::string s, uint64_t *v)
|
||||
{
|
||||
std::string::size_type n = s.find_first_not_of("0123456789.");
|
||||
@@ -123,7 +122,6 @@ DoParse (const std::string s, uint64_t *v)
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
|
||||
@@ -41,9 +41,26 @@ class Header : public Chunk {
|
||||
public:
|
||||
virtual ~Header ();
|
||||
private:
|
||||
/**
|
||||
* \returns a user-readable name to identify this type of header.
|
||||
*
|
||||
* The string returned is expected to be a single word with
|
||||
* all capital letters
|
||||
*/
|
||||
virtual std::string DoGetName (void) const = 0;
|
||||
/**
|
||||
* \param os the std output stream in which this
|
||||
* protocol header must print itself.
|
||||
*
|
||||
* Although the header is free to format its output as it
|
||||
* wishes, it is recommended to follow a few rules to integrate
|
||||
* with the packet pretty printer:
|
||||
* - start with flags, small field values located between a
|
||||
* pair of parens. Values should be separated by whitespace.
|
||||
* - follow the parens with the important fields, separated by
|
||||
* whitespace.
|
||||
* i.e.:
|
||||
* (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
|
||||
*/
|
||||
virtual void PrintTo (std::ostream &os) const = 0;
|
||||
|
||||
|
||||
1714
src/common/packet-metadata.cc
Normal file
1714
src/common/packet-metadata.cc
Normal file
File diff suppressed because it is too large
Load Diff
335
src/common/packet-metadata.h
Normal file
335
src/common/packet-metadata.h
Normal file
@@ -0,0 +1,335 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006,2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef PACKET_METADATA_H
|
||||
#define PACKET_METADATA_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/assert.h"
|
||||
#include "packet-printer.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Chunk;
|
||||
class Buffer;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
* \brief handle packet metadata about packet headers and trailers
|
||||
*
|
||||
* This class is used by the Packet class to record every operation
|
||||
* performed on the packet's buffer. This class also provides
|
||||
* an implementation of the Packet::Print methods which uses
|
||||
* the metadata to analyse the content of the packet's buffer.
|
||||
*
|
||||
* To achieve this, this class maintains a linked list of so-called
|
||||
* "items", each of which represents a header or a trailer, or
|
||||
* payload, or a fragment of any of these. Each item contains a "next"
|
||||
* and a "prev" field which point to the next and previous entries
|
||||
* in the linked list. The PacketMetadata class maintains a pair
|
||||
* of pointers to the head and the tail of the linked list.
|
||||
*
|
||||
* Each entry in the list also maintains:
|
||||
* - its native size (the size it had when it was first added
|
||||
* to the packet)
|
||||
* - its type: identifies what kind of header, what kind of trailer,
|
||||
* if it is payload or not
|
||||
* - the uid of the packet to which it was first added
|
||||
* - the start and end of the area represented by a fragment
|
||||
* if it is one.
|
||||
*
|
||||
* This linked list is flattened in a byte buffer stored in
|
||||
* struct PacketMetadata::Data. Each entry of the linked list is
|
||||
* identified by an offset which identifies the first byte of the
|
||||
* entry from the start of the data buffer. The size of this data
|
||||
* buffer is 2^16-1 bytes maximum which somewhat limits the number
|
||||
* of entries which can be stored in this linked list but it is
|
||||
* quite unlikely to hit this limit in practice.
|
||||
*
|
||||
* Each item of the linked list is a variable-sized byte buffer
|
||||
* made of a number of fields. Some of these fields are stored
|
||||
* as fixed-size 32 bit integers, others as fixed-size 16 bit
|
||||
* integers, and some others as variable-size 32-bit integers.
|
||||
* The variable-size 32 bit integers are stored using the uleb128
|
||||
* encoding.
|
||||
*/
|
||||
class PacketMetadata {
|
||||
public:
|
||||
static void Enable (void);
|
||||
static void SetOptOne (bool optOne);
|
||||
|
||||
inline PacketMetadata (uint32_t uid, uint32_t size);
|
||||
inline PacketMetadata (PacketMetadata const &o);
|
||||
inline PacketMetadata &operator = (PacketMetadata const& o);
|
||||
inline ~PacketMetadata ();
|
||||
|
||||
template <typename T>
|
||||
void AddHeader (T const &header, uint32_t size);
|
||||
template <typename T>
|
||||
void RemoveHeader (T const &header, uint32_t size);
|
||||
|
||||
template <typename T>
|
||||
void AddTrailer (T const &trailer, uint32_t size);
|
||||
template <typename T>
|
||||
void RemoveTrailer (T const &trailer, uint32_t size);
|
||||
|
||||
PacketMetadata CreateFragment (uint32_t start, uint32_t end) const;
|
||||
void AddAtEnd (PacketMetadata const&o);
|
||||
void AddPaddingAtEnd (uint32_t end);
|
||||
void RemoveAtStart (uint32_t start);
|
||||
void RemoveAtEnd (uint32_t end);
|
||||
|
||||
uint32_t GetUid (void) const;
|
||||
|
||||
void PrintDefault (std::ostream &os, Buffer buffer) const;
|
||||
void Print (std::ostream &os, Buffer buffer, PacketPrinter const &printer) const;
|
||||
|
||||
static void PrintStats (void);
|
||||
|
||||
private:
|
||||
struct Data {
|
||||
/* number of references to this struct Data instance. */
|
||||
uint16_t m_count;
|
||||
/* size (in bytes) of m_data buffer below */
|
||||
uint16_t m_size;
|
||||
/* max of the m_used field over all objects which
|
||||
* reference this struct Data instance */
|
||||
uint16_t m_dirtyEnd;
|
||||
/* variable-sized buffer of bytes */
|
||||
uint8_t m_data[10];
|
||||
};
|
||||
/* Note that since the next and prev fields are 16 bit integers
|
||||
and since the value 0xffff is reserved to identify the
|
||||
fact that the end or the start of the list is reached,
|
||||
only a limited number of elements can be stored in
|
||||
a m_data byte buffer.
|
||||
*/
|
||||
struct SmallItem {
|
||||
/* offset (in bytes) from start of m_data buffer
|
||||
to next element in linked list. value is 0xffff
|
||||
if next element does not exist.
|
||||
stored as a fixed-size 16 bit integer.
|
||||
*/
|
||||
uint16_t next;
|
||||
/* offset (in bytes) from start of m_data buffer
|
||||
to previous element in linked list. value is 0xffff
|
||||
if previous element does not exist.
|
||||
stored as a fixed-size 16 bit integer.
|
||||
*/
|
||||
uint16_t prev;
|
||||
/* the high 31 bits of this field identify the
|
||||
type of the header or trailer represented by
|
||||
this item: the value zero represents payload.
|
||||
If the low bit of this uid is one, an ExtraItem
|
||||
structure follows this SmallItem structure.
|
||||
stored as a variable-size 32 bit integer.
|
||||
*/
|
||||
uint32_t typeUid;
|
||||
/* the size (in bytes) of the header or trailer represented
|
||||
by this element.
|
||||
stored as a variable-size 32 bit integer.
|
||||
*/
|
||||
uint32_t size;
|
||||
/* this field tries to uniquely identify each header or
|
||||
trailer _instance_ while the typeUid field uniquely
|
||||
identifies each header or trailer _type_. This field
|
||||
is used to test whether two items are equal in the sense
|
||||
that they represent the same header or trailer instance.
|
||||
That equality test is based on the typeUid and chunkUid
|
||||
fields so, the likelyhood that two header instances
|
||||
share the same chunkUid _and_ typeUid is very small
|
||||
unless they are really representations of the same header
|
||||
instance.
|
||||
stored as a fixed-size 16 bit integer.
|
||||
*/
|
||||
uint16_t chunkUid;
|
||||
};
|
||||
struct ExtraItem {
|
||||
/* offset (in bytes) from start of original header to
|
||||
the start of the fragment still present.
|
||||
stored as a variable-size 32 bit integer.
|
||||
*/
|
||||
uint32_t fragmentStart;
|
||||
/* offset (in bytes) from start of original header to
|
||||
the end of the fragment still present.
|
||||
stored as a variable-size 32 bit integer.
|
||||
*/
|
||||
uint32_t fragmentEnd;
|
||||
/* the packetUid of the packet in which this header or trailer
|
||||
was first added. It could be different from the m_packetUid
|
||||
field if the user has aggregated multiple packets into one.
|
||||
stored as a fixed-size 32 bit integer.
|
||||
*/
|
||||
uint32_t packetUid;
|
||||
};
|
||||
|
||||
typedef std::vector<struct Data *> DataFreeList;
|
||||
|
||||
PacketMetadata ();
|
||||
void DoAddHeader (uint32_t uid, uint32_t size);
|
||||
void DoRemoveHeader (uint32_t uid, uint32_t size);
|
||||
void DoAddTrailer (uint32_t uid, uint32_t size);
|
||||
void DoRemoveTrailer (uint32_t uid, uint32_t size);
|
||||
|
||||
inline uint16_t AddSmall (const PacketMetadata::SmallItem *item);
|
||||
uint16_t AddBig (uint32_t head, uint32_t tail,
|
||||
const PacketMetadata::SmallItem *item,
|
||||
const PacketMetadata::ExtraItem *extraItem);
|
||||
void ReplaceTail (PacketMetadata::SmallItem *item,
|
||||
PacketMetadata::ExtraItem *extraItem,
|
||||
uint32_t available);
|
||||
inline void UpdateHead (uint16_t written);
|
||||
inline void UpdateTail (uint16_t written);
|
||||
uint32_t GetUleb128Size (uint32_t value) const;
|
||||
uint32_t ReadUleb128 (const uint8_t **pBuffer) const;
|
||||
inline void Append16 (uint16_t value, uint8_t *buffer);
|
||||
inline bool TryToAppend (uint32_t value, uint8_t **pBuffer, uint8_t *end);
|
||||
inline bool TryToAppendFast (uint32_t value, uint8_t **pBuffer, uint8_t *end);
|
||||
inline bool TryToAppend32 (uint32_t value, uint8_t **pBuffer, uint8_t *end);
|
||||
inline bool TryToAppend16 (uint16_t value, uint8_t **pBuffer, uint8_t *end);
|
||||
void AppendValue (uint32_t value, uint8_t *buffer);
|
||||
void AppendValueExtra (uint32_t value, uint8_t *buffer);
|
||||
inline void Reserve (uint32_t n);
|
||||
void ReserveCopy (uint32_t n);
|
||||
uint32_t DoPrint (const struct PacketMetadata::SmallItem *item,
|
||||
const struct PacketMetadata::ExtraItem *extraItem,
|
||||
Buffer data, uint32_t offset, const PacketPrinter &printer,
|
||||
std::ostream &os) const;
|
||||
uint32_t GetTotalSize (void) const;
|
||||
uint32_t ReadItems (uint16_t current,
|
||||
struct PacketMetadata::SmallItem *item,
|
||||
struct PacketMetadata::ExtraItem *extraItem) const;
|
||||
|
||||
|
||||
static struct PacketMetadata::Data *Create (uint32_t size);
|
||||
static void Recycle (struct PacketMetadata::Data *data);
|
||||
static struct PacketMetadata::Data *Allocate (uint32_t n);
|
||||
static void Deallocate (struct PacketMetadata::Data *data);
|
||||
|
||||
static DataFreeList m_freeList;
|
||||
static bool m_enable;
|
||||
static uint32_t m_maxSize;
|
||||
static uint16_t m_chunkUid;
|
||||
|
||||
struct Data *m_data;
|
||||
/**
|
||||
head -(next)-> tail
|
||||
^ |
|
||||
\---(prev)---|
|
||||
*/
|
||||
uint16_t m_head;
|
||||
uint16_t m_tail;
|
||||
uint16_t m_used;
|
||||
uint32_t m_packetUid;
|
||||
};
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
PacketMetadata::AddHeader (T const &header, uint32_t size)
|
||||
{
|
||||
DoAddHeader (PacketPrinter::GetHeaderUid<T> (), size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
PacketMetadata::RemoveHeader (T const &header, uint32_t size)
|
||||
{
|
||||
DoRemoveHeader (PacketPrinter::GetHeaderUid<T> (), size);
|
||||
}
|
||||
template <typename T>
|
||||
void
|
||||
PacketMetadata::AddTrailer (T const &trailer, uint32_t size)
|
||||
{
|
||||
DoAddTrailer (PacketPrinter::GetTrailerUid<T> (), size);
|
||||
}
|
||||
template <typename T>
|
||||
void
|
||||
PacketMetadata::RemoveTrailer (T const &trailer, uint32_t size)
|
||||
{
|
||||
DoRemoveTrailer (PacketPrinter::GetTrailerUid<T> (), size);
|
||||
}
|
||||
|
||||
|
||||
PacketMetadata::PacketMetadata (uint32_t uid, uint32_t size)
|
||||
: m_data (m_data = PacketMetadata::Create (10)),
|
||||
m_head (0xffff),
|
||||
m_tail (0xffff),
|
||||
m_used (0),
|
||||
m_packetUid (uid)
|
||||
{
|
||||
memset (m_data->m_data, 0xff, 4);
|
||||
if (size > 0)
|
||||
{
|
||||
DoAddHeader (0, size);
|
||||
}
|
||||
}
|
||||
PacketMetadata::PacketMetadata (PacketMetadata const &o)
|
||||
: m_data (o.m_data),
|
||||
m_head (o.m_head),
|
||||
m_tail (o.m_tail),
|
||||
m_used (o.m_used),
|
||||
m_packetUid (o.m_packetUid)
|
||||
{
|
||||
NS_ASSERT (m_data != 0);
|
||||
m_data->m_count++;
|
||||
}
|
||||
PacketMetadata &
|
||||
PacketMetadata::operator = (PacketMetadata const& o)
|
||||
{
|
||||
if (m_data == o.m_data)
|
||||
{
|
||||
// self assignment
|
||||
return *this;
|
||||
}
|
||||
NS_ASSERT (m_data != 0);
|
||||
m_data->m_count--;
|
||||
if (m_data->m_count == 0)
|
||||
{
|
||||
PacketMetadata::Recycle (m_data);
|
||||
}
|
||||
m_data = o.m_data;
|
||||
m_head = o.m_head;
|
||||
m_tail = o.m_tail;
|
||||
m_used = o.m_used;
|
||||
m_packetUid = o.m_packetUid;
|
||||
NS_ASSERT (m_data != 0);
|
||||
m_data->m_count++;
|
||||
return *this;
|
||||
}
|
||||
PacketMetadata::~PacketMetadata ()
|
||||
{
|
||||
NS_ASSERT (m_data != 0);
|
||||
m_data->m_count--;
|
||||
if (m_data->m_count == 0)
|
||||
{
|
||||
PacketMetadata::Recycle (m_data);
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
#endif /* PACKET_METADATA_H */
|
||||
235
src/common/packet-printer.cc
Normal file
235
src/common/packet-printer.cc
Normal file
@@ -0,0 +1,235 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#include "packet-printer.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
PacketPrinter::PacketPrinter ()
|
||||
: m_forward (true),
|
||||
m_separator ("")
|
||||
{}
|
||||
|
||||
void
|
||||
PacketPrinter::PrintForward (void)
|
||||
{
|
||||
m_forward = true;
|
||||
}
|
||||
void
|
||||
PacketPrinter::PrintBackward (void)
|
||||
{
|
||||
m_forward = false;
|
||||
}
|
||||
void
|
||||
PacketPrinter::SetSeparator (std::string separator)
|
||||
{
|
||||
m_separator = separator;
|
||||
}
|
||||
void
|
||||
PacketPrinter::AddPayloadPrinter (PayloadPrinter printer)
|
||||
{
|
||||
m_payloadPrinter = printer;
|
||||
}
|
||||
void
|
||||
PacketPrinter::AddDefaultPrinter (DefaultPrinter printer)
|
||||
{
|
||||
m_defaultPrinter = printer;
|
||||
}
|
||||
|
||||
PacketPrinter::RegisteredChunks *
|
||||
PacketPrinter::GetRegisteredChunks (void)
|
||||
{
|
||||
static RegisteredChunks registeredChunks;
|
||||
return ®isteredChunks;
|
||||
}
|
||||
|
||||
PacketPrinter
|
||||
PacketPrinter::GetDefault (void)
|
||||
{
|
||||
return *(PacketPrinter::PeekDefault ());
|
||||
}
|
||||
PacketPrinter *
|
||||
PacketPrinter::PeekDefault (void)
|
||||
{
|
||||
static PacketPrinter *tmp = PacketPrinter::CreateStaticDefault ();
|
||||
return tmp;
|
||||
}
|
||||
PacketPrinter *
|
||||
PacketPrinter::CreateStaticDefault (void)
|
||||
{
|
||||
static PacketPrinter tmp;
|
||||
tmp.PrintForward ();
|
||||
tmp.AddPayloadPrinter (MakeCallback (&PacketPrinter::DoDefaultPrintPayload));
|
||||
tmp.SetSeparator (" ");
|
||||
return &tmp;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PacketPrinter::PrintChunk (uint32_t chunkUid,
|
||||
Buffer::Iterator start,
|
||||
std::ostream &os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size) const
|
||||
{
|
||||
RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
|
||||
NS_ASSERT (chunkUid >= 1 && chunkUid/2 <= registeredChunks->size ());
|
||||
for (PrinterList::const_iterator i = m_printerList.begin (); i != m_printerList.end (); i++)
|
||||
{
|
||||
if (i->m_chunkUid == chunkUid)
|
||||
{
|
||||
DoPrintCallback cb = (*registeredChunks)[chunkUid/2-1].printCallback;
|
||||
cb (i->m_printer, start, os, packetUid, size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
DoGetNameCallback cb = (*registeredChunks)[chunkUid/2-1].getNameCallback;
|
||||
std::string name = cb ();
|
||||
struct PacketPrinter::FragmentInformation info;
|
||||
info.start = 0;
|
||||
info.end = 0;
|
||||
if (!m_defaultPrinter.IsNull ())
|
||||
{
|
||||
m_defaultPrinter (os, packetUid, size, name, info);
|
||||
}
|
||||
}
|
||||
void
|
||||
PacketPrinter::PrintChunkFragment (uint32_t chunkUid,
|
||||
std::ostream &os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size,
|
||||
uint32_t fragmentStart,
|
||||
uint32_t fragmentEnd) const
|
||||
{
|
||||
RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
|
||||
NS_ASSERT (chunkUid >= 1 && chunkUid/2 <= registeredChunks->size ());
|
||||
DoGetNameCallback cb = (*registeredChunks)[chunkUid/2-1].getNameCallback;
|
||||
std::string name = cb ();
|
||||
struct PacketPrinter::FragmentInformation info;
|
||||
info.start = fragmentStart;
|
||||
info.end = fragmentEnd;
|
||||
for (PrinterList::const_iterator i = m_printerList.begin (); i != m_printerList.end (); i++)
|
||||
{
|
||||
if (i->m_chunkUid == chunkUid)
|
||||
{
|
||||
i->m_fragmentPrinter (os, packetUid, size, name, info);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!m_defaultPrinter.IsNull ())
|
||||
{
|
||||
m_defaultPrinter (os, packetUid, size, name, info);
|
||||
}
|
||||
}
|
||||
void
|
||||
PacketPrinter::PrintPayload (std::ostream &os, uint32_t packetUid, uint32_t size,
|
||||
uint32_t fragmentStart, uint32_t fragmentEnd) const
|
||||
{
|
||||
struct PacketPrinter::FragmentInformation info;
|
||||
info.start = fragmentStart;
|
||||
info.end = fragmentEnd;
|
||||
if (!m_payloadPrinter.IsNull ())
|
||||
{
|
||||
m_payloadPrinter (os, packetUid, size, info);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PacketPrinter::DoDefaultPrintPayload (std::ostream & os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size,
|
||||
struct PacketPrinter::FragmentInformation info)
|
||||
{
|
||||
os << "DATA ("
|
||||
<< "length " << size - (info.end + info.start);
|
||||
if (info.start != 0 || info.end != 0)
|
||||
{
|
||||
os << " "
|
||||
<< "trim_start " << info.start << " "
|
||||
<< "trim_end " << info.end;
|
||||
}
|
||||
os << ")";
|
||||
}
|
||||
|
||||
void
|
||||
PacketPrinter::DoDefaultPrintDefault (std::ostream & os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size,
|
||||
std::string &name,
|
||||
struct PacketPrinter::FragmentInformation info)
|
||||
{
|
||||
NS_ASSERT_MSG (false, "This should never happen because we provide a printer for _all_ chunk types.");
|
||||
}
|
||||
|
||||
void
|
||||
PacketPrinter::DoDefaultPrintFragment (std::ostream & os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size,
|
||||
std::string &name,
|
||||
struct PacketPrinter::FragmentInformation info)
|
||||
{
|
||||
NS_ASSERT (info.start != 0 || info.end != 0);
|
||||
os << name << " "
|
||||
<< "("
|
||||
<< "length " << size - (info.end + info.start) << " "
|
||||
<< "trim_start " << info.start << " "
|
||||
<< "trim_end " << info.end
|
||||
<< ")"
|
||||
;
|
||||
}
|
||||
|
||||
void
|
||||
PacketPrinter::DoAddPrinter (uint32_t uid,
|
||||
Ptr<CallbackImplBase> printer,
|
||||
Callback<void,
|
||||
std::ostream &,
|
||||
uint32_t,
|
||||
uint32_t,
|
||||
std::string &,
|
||||
struct PacketPrinter::FragmentInformation> fragmentPrinter)
|
||||
{
|
||||
struct PacketPrinter::Printer p;
|
||||
p.m_chunkUid = uid;
|
||||
p.m_printer = printer;
|
||||
p.m_fragmentPrinter = fragmentPrinter;
|
||||
m_printerList.push_back (p);
|
||||
}
|
||||
|
||||
bool
|
||||
PacketPrinter::IsTrailer (uint32_t uid)
|
||||
{
|
||||
RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
|
||||
NS_ASSERT (uid >= 1 && uid/2 <= registeredChunks->size ());
|
||||
bool isHeader = (*registeredChunks)[uid/2-1].isHeader;
|
||||
return !isHeader;
|
||||
}
|
||||
bool
|
||||
PacketPrinter::IsHeader (uint32_t uid)
|
||||
{
|
||||
RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
|
||||
NS_ASSERT (uid >= 1 && uid/2 <= registeredChunks->size ());
|
||||
bool isHeader = (*registeredChunks)[uid/2-1].isHeader;
|
||||
return isHeader;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
318
src/common/packet-printer.h
Normal file
318
src/common/packet-printer.h
Normal file
@@ -0,0 +1,318 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef PACKET_PRINTER_H
|
||||
#define PACKET_PRINTER_H
|
||||
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "buffer.h"
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
class ItemList;
|
||||
}
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Chunk;
|
||||
|
||||
/**
|
||||
* \brief hold a list of print callbacks for packet headers and trailers
|
||||
*
|
||||
* Users can register in instances of this class print callbacks
|
||||
* which are used by Packet::Print to print the content of a packet.
|
||||
*/
|
||||
class PacketPrinter
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief indicates how many bytes were trimmed from a header
|
||||
* or a trailer.
|
||||
*/
|
||||
struct FragmentInformation
|
||||
{
|
||||
/**
|
||||
* The number of bytes trimmed from the start of the header or the trailer.
|
||||
*/
|
||||
uint32_t start;
|
||||
/**
|
||||
* The number of bytes trimmed from the end of the header or the trailer.
|
||||
*/
|
||||
uint32_t end;
|
||||
};
|
||||
/**
|
||||
* \brief callback to print payload.
|
||||
*
|
||||
* Arguments: output stream, packet uid, size, fragment information
|
||||
*/
|
||||
typedef Callback<void,std::ostream &,uint32_t,uint32_t,struct PacketPrinter::FragmentInformation>
|
||||
PayloadPrinter;
|
||||
|
||||
/**
|
||||
* \brief callback to print fragmented chunks.
|
||||
*
|
||||
* Arguments: output stream, packet uid, size, header/trailer name, fragment information
|
||||
*/
|
||||
typedef Callback<void,std::ostream &,uint32_t,uint32_t,std::string &,struct PacketPrinter::FragmentInformation>
|
||||
ChunkFragmentPrinter;
|
||||
|
||||
/**
|
||||
* \brief callback to print chunks for which no specific callback was specified.
|
||||
*
|
||||
* Arguments: output stream, packet uid, size, header/trailer name, fragment information
|
||||
*/
|
||||
typedef Callback<void,std::ostream&,uint32_t,uint32_t,std::string&,struct PacketPrinter::FragmentInformation>
|
||||
DefaultPrinter;
|
||||
|
||||
PacketPrinter ();
|
||||
|
||||
/**
|
||||
* Print the content of the packet forward.
|
||||
*/
|
||||
void PrintForward (void);
|
||||
/**
|
||||
* Print the content of the packet backward.
|
||||
*/
|
||||
void PrintBackward (void);
|
||||
void SetSeparator (std::string separator);
|
||||
/**
|
||||
* \param printer printer for payload
|
||||
*/
|
||||
void AddPayloadPrinter (PayloadPrinter printer);
|
||||
/**
|
||||
* \param printer printer for the specified chunk
|
||||
* \param fragmentPrinter printer for a fragment of the specified chunk
|
||||
*
|
||||
* If the user has not specified a callback for a specific header present
|
||||
* in a packet, the "default" callback is invoked. If no such callback
|
||||
* was specified, nothing happens.
|
||||
*/
|
||||
template <typename T>
|
||||
void AddHeaderPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
|
||||
ChunkFragmentPrinter fragmentPrinter);
|
||||
/**
|
||||
* \param printer printer for the specified chunk
|
||||
* \param fragmentPrinter printer for a fragment of the specified chunk
|
||||
*
|
||||
* If the user has not specified a callback for a specific trailer present
|
||||
* in a packet, the "default" callback is invoked. If no such callback
|
||||
* was specified, nothing happens.
|
||||
*/
|
||||
template <typename T>
|
||||
void AddTrailerPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
|
||||
ChunkFragmentPrinter fragmentPrinter);
|
||||
/**
|
||||
* \param printer printer for a chunk for which no callback was specified explicitely
|
||||
*/
|
||||
void AddDefaultPrinter (DefaultPrinter printer);
|
||||
|
||||
private:
|
||||
friend class PacketMetadata;
|
||||
typedef void (*DoPrintCallback) (Ptr<CallbackImplBase>, Buffer::Iterator, std::ostream &,
|
||||
uint32_t, uint32_t);
|
||||
typedef std::string (*DoGetNameCallback) (void);
|
||||
struct Printer
|
||||
{
|
||||
uint32_t m_chunkUid;
|
||||
Ptr<CallbackImplBase> m_printer;
|
||||
Callback<void,std::ostream &,uint32_t,uint32_t,std::string &,struct PacketPrinter::FragmentInformation>
|
||||
m_fragmentPrinter;
|
||||
};
|
||||
struct RegisteredChunk
|
||||
{
|
||||
DoPrintCallback printCallback;
|
||||
DoGetNameCallback getNameCallback;
|
||||
bool isHeader;
|
||||
};
|
||||
typedef std::vector<struct PacketPrinter::Printer> PrinterList;
|
||||
typedef std::vector<struct RegisteredChunk> RegisteredChunks;
|
||||
|
||||
|
||||
static PacketPrinter GetDefault (void);
|
||||
static PacketPrinter *PeekDefault (void);
|
||||
static PacketPrinter *CreateStaticDefault (void);
|
||||
static void DoDefaultPrintPayload (std::ostream & os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size,
|
||||
struct PacketPrinter::FragmentInformation info);
|
||||
static void DoDefaultPrintDefault (std::ostream & os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size,
|
||||
std::string &name,
|
||||
struct PacketPrinter::FragmentInformation info);
|
||||
template <typename T>
|
||||
static void DoDefaultPrint (std::ostream &os, uint32_t packetUid, uint32_t size, const T *chunk);
|
||||
static void DoDefaultPrintFragment (std::ostream & os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size,
|
||||
std::string &name,
|
||||
struct PacketPrinter::FragmentInformation info);
|
||||
|
||||
template <typename T>
|
||||
static void DoPrint (Ptr<CallbackImplBase> callbackPrinter,
|
||||
Buffer::Iterator i,
|
||||
std::ostream &os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size);
|
||||
template <typename T>
|
||||
static std::string DoGetName (void);
|
||||
template <typename T>
|
||||
static uint32_t GetTrailerUid (void);
|
||||
template <typename T>
|
||||
static uint32_t GetHeaderUid (void);
|
||||
template <typename T>
|
||||
static uint32_t AllocateUid (bool isHeader);
|
||||
static RegisteredChunks *GetRegisteredChunks (void);
|
||||
static bool IsTrailer (uint32_t uid);
|
||||
static bool IsHeader (uint32_t uid);
|
||||
|
||||
|
||||
void PrintChunk (uint32_t uid,
|
||||
Buffer::Iterator i,
|
||||
std::ostream &os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size) const;
|
||||
void PrintChunkFragment (uint32_t uid,
|
||||
std::ostream &os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size,
|
||||
uint32_t fragmentStart,
|
||||
uint32_t fragmentEnd) const;
|
||||
void PrintPayload (std::ostream &os, uint32_t packetUid, uint32_t size,
|
||||
uint32_t fragmentStart, uint32_t fragmentEnd) const;
|
||||
void DoAddPrinter (uint32_t uid,
|
||||
Ptr<CallbackImplBase> printer,
|
||||
Callback<void,
|
||||
std::ostream &,
|
||||
uint32_t,
|
||||
uint32_t,
|
||||
std::string &,
|
||||
struct PacketPrinter::FragmentInformation> fragmentPrinter);
|
||||
|
||||
static PacketPrinter m_defaultPacketPrinter;
|
||||
PrinterList m_printerList;
|
||||
PayloadPrinter m_payloadPrinter;
|
||||
DefaultPrinter m_defaultPrinter;
|
||||
bool m_forward;
|
||||
std::string m_separator;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
PacketPrinter::AddHeaderPrinter (Callback<void,std::ostream &, uint32_t, uint32_t, const T *> printer,
|
||||
Callback<void,
|
||||
std::ostream &,
|
||||
uint32_t,
|
||||
uint32_t,
|
||||
std::string &,
|
||||
struct PacketPrinter::FragmentInformation> fragmentPrinter)
|
||||
{
|
||||
static uint32_t uid = PacketPrinter::GetHeaderUid<T> ();
|
||||
DoAddPrinter (uid, printer.GetImpl (), fragmentPrinter);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
PacketPrinter::AddTrailerPrinter (Callback<void,std::ostream &, uint32_t, uint32_t, const T *> printer,
|
||||
Callback<void,
|
||||
std::ostream &,
|
||||
uint32_t,
|
||||
uint32_t,
|
||||
std::string &,
|
||||
struct PacketPrinter::FragmentInformation> fragmentPrinter)
|
||||
{
|
||||
static uint32_t uid = PacketPrinter::GetTrailerUid<T> ();
|
||||
DoAddPrinter (uid, printer.GetImpl (), fragmentPrinter);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
PacketPrinter::DoPrint (Ptr<CallbackImplBase> printerCallback,
|
||||
Buffer::Iterator i,
|
||||
std::ostream &os,
|
||||
uint32_t packetUid,
|
||||
uint32_t size)
|
||||
{
|
||||
T chunk = T ();
|
||||
chunk.Deserialize (i);
|
||||
Callback<void,std::ostream&,uint32_t,uint32_t,const T*> callback;
|
||||
callback.Assign (printerCallback);
|
||||
callback (os, packetUid, size, &chunk);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string
|
||||
PacketPrinter::DoGetName (void)
|
||||
{
|
||||
T chunk = T ();
|
||||
return chunk.GetName ();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
uint32_t
|
||||
PacketPrinter::GetHeaderUid (void)
|
||||
{
|
||||
static uint32_t uid = PacketPrinter::AllocateUid<T> (true);
|
||||
return uid;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
uint32_t
|
||||
PacketPrinter::GetTrailerUid (void)
|
||||
{
|
||||
static uint32_t uid = PacketPrinter::AllocateUid<T> (false);
|
||||
return uid;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
uint32_t
|
||||
PacketPrinter::AllocateUid (bool isHeader)
|
||||
{
|
||||
RegisteredChunks *chunks = PacketPrinter::GetRegisteredChunks ();
|
||||
RegisteredChunk chunk;
|
||||
chunk.printCallback = &PacketPrinter::DoPrint<T>;
|
||||
chunk.getNameCallback = &PacketPrinter::DoGetName<T>;
|
||||
chunk.isHeader = isHeader;
|
||||
chunks->push_back (chunk);
|
||||
uint32_t uid = chunks->size () * 2;
|
||||
PacketPrinter::PeekDefault ()->DoAddPrinter (uid,
|
||||
MakeCallback (&PacketPrinter::DoDefaultPrint<T>).GetImpl (),
|
||||
MakeCallback (&PacketPrinter::DoDefaultPrintFragment));
|
||||
return uid;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
PacketPrinter::DoDefaultPrint (std::ostream &os, uint32_t packetUid, uint32_t size, const T *chunk)
|
||||
{
|
||||
os << chunk->GetName () << " ";
|
||||
chunk->Print (os);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* PACKET_PRINTER_H */
|
||||
@@ -19,6 +19,7 @@
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "packet.h"
|
||||
#include "packet-printer.h"
|
||||
#include "ns3/assert.h"
|
||||
|
||||
namespace ns3 {
|
||||
@@ -27,20 +28,20 @@ uint32_t Packet::m_globalUid = 0;
|
||||
|
||||
Packet::Packet ()
|
||||
: m_buffer (),
|
||||
m_uid (m_globalUid)
|
||||
m_metadata (m_globalUid, 0)
|
||||
{
|
||||
m_globalUid++;
|
||||
}
|
||||
|
||||
Packet::Packet (uint32_t size)
|
||||
: m_buffer (size),
|
||||
m_uid (m_globalUid)
|
||||
m_metadata (m_globalUid, size)
|
||||
{
|
||||
m_globalUid++;
|
||||
}
|
||||
Packet::Packet (uint8_t const*buffer, uint32_t size)
|
||||
: m_buffer (),
|
||||
m_uid (m_globalUid)
|
||||
m_metadata (m_globalUid, size)
|
||||
{
|
||||
m_globalUid++;
|
||||
m_buffer.AddAtStart (size);
|
||||
@@ -48,17 +49,20 @@ Packet::Packet (uint8_t const*buffer, uint32_t size)
|
||||
i.Write (buffer, size);
|
||||
}
|
||||
|
||||
Packet::Packet (Buffer buffer, Tags tags, uint32_t uid)
|
||||
Packet::Packet (Buffer buffer, Tags tags, PacketMetadata metadata)
|
||||
: m_buffer (buffer),
|
||||
m_tags (tags),
|
||||
m_uid (uid)
|
||||
m_metadata (metadata)
|
||||
{}
|
||||
|
||||
Packet
|
||||
Packet::CreateFragment (uint32_t start, uint32_t length) const
|
||||
{
|
||||
Buffer buffer = m_buffer.CreateFragment (start, length);
|
||||
return Packet (buffer, m_tags, m_uid);
|
||||
NS_ASSERT (m_buffer.GetSize () >= start + length);
|
||||
uint32_t end = m_buffer.GetSize () - (start + length);
|
||||
PacketMetadata metadata = m_metadata.CreateFragment (start, end);
|
||||
return Packet (buffer, m_tags, metadata);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
@@ -70,6 +74,9 @@ Packet::GetSize (void) const
|
||||
void
|
||||
Packet::AddAtEnd (Packet packet)
|
||||
{
|
||||
packet.m_buffer.TransformIntoRealBuffer ();
|
||||
m_buffer.TransformIntoRealBuffer ();
|
||||
|
||||
Buffer src = packet.m_buffer;
|
||||
m_buffer.AddAtEnd (src.GetSize ());
|
||||
Buffer::Iterator destStart = m_buffer.End ();
|
||||
@@ -79,21 +86,25 @@ Packet::AddAtEnd (Packet packet)
|
||||
* XXX: we might need to merge the tag list of the
|
||||
* other packet into the current packet.
|
||||
*/
|
||||
m_metadata.AddAtEnd (packet.m_metadata);
|
||||
}
|
||||
void
|
||||
Packet::AddPaddingAtEnd (uint32_t size)
|
||||
{
|
||||
m_buffer.AddAtEnd (size);
|
||||
m_metadata.AddPaddingAtEnd (size);
|
||||
}
|
||||
void
|
||||
Packet::RemoveAtEnd (uint32_t size)
|
||||
{
|
||||
m_buffer.RemoveAtEnd (size);
|
||||
m_metadata.RemoveAtEnd (size);
|
||||
}
|
||||
void
|
||||
Packet::RemoveAtStart (uint32_t size)
|
||||
{
|
||||
m_buffer.RemoveAtStart (size);
|
||||
m_metadata.RemoveAtStart (size);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -111,12 +122,26 @@ Packet::PeekData (void) const
|
||||
uint32_t
|
||||
Packet::GetUid (void) const
|
||||
{
|
||||
return m_uid;
|
||||
return m_metadata.GetUid ();
|
||||
}
|
||||
|
||||
void
|
||||
Packet::Print (std::ostream &os) const
|
||||
{}
|
||||
{
|
||||
m_metadata.PrintDefault (os, m_buffer);
|
||||
}
|
||||
|
||||
void
|
||||
Packet::Print (std::ostream &os, const PacketPrinter &printer) const
|
||||
{
|
||||
m_metadata.Print (os, m_buffer, printer);
|
||||
}
|
||||
|
||||
void
|
||||
Packet::EnableMetadata (void)
|
||||
{
|
||||
PacketMetadata::Enable ();
|
||||
}
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
@@ -26,11 +26,14 @@
|
||||
#include "header.h"
|
||||
#include "trailer.h"
|
||||
#include "tags.h"
|
||||
#include "packet-metadata.h"
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/assert.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class PacketPrinter;
|
||||
|
||||
/**
|
||||
* \brief network packets
|
||||
*
|
||||
@@ -129,7 +132,7 @@ public:
|
||||
uint32_t GetSize (void) const;
|
||||
/**
|
||||
* Add header to this packet. This method invokes the
|
||||
* ns3::Header::GetSerializedSize and ns3::Header::SerializeTo
|
||||
* ns3::Chunk::GetSerializedSize and ns3::Chunk::SerializeTo
|
||||
* methods to reserve space in the buffer and request the
|
||||
* header to serialize itself in the packet buffer.
|
||||
*
|
||||
@@ -139,8 +142,7 @@ public:
|
||||
void AddHeader (T const &header);
|
||||
/**
|
||||
* Deserialize and remove the header from the internal buffer.
|
||||
* This method invokes ns3::Header::DeserializeFrom
|
||||
* and then removes the deserialized bytes from the buffer.
|
||||
* This method invokes ns3::Chunk::DeserializeFrom.
|
||||
*
|
||||
* \param header a reference to the header to remove from the internal buffer.
|
||||
* \returns the number of bytes removed from the packet.
|
||||
@@ -149,7 +151,7 @@ public:
|
||||
uint32_t RemoveHeader (T &header);
|
||||
/**
|
||||
* Add trailer to this packet. This method invokes the
|
||||
* ns3::Trailer::GetSerializedSize and ns3::Trailer::serializeTo
|
||||
* ns3::Chunk::GetSerializedSize and ns3::Trailer::serializeTo
|
||||
* methods to reserve space in the buffer and request the trailer
|
||||
* to serialize itself in the packet buffer.
|
||||
*
|
||||
@@ -159,8 +161,7 @@ public:
|
||||
void AddTrailer (T const &trailer);
|
||||
/**
|
||||
* Remove a deserialized trailer from the internal buffer.
|
||||
* This method invokes the ns3::Trailer::DeserializeFrom method
|
||||
* and then removes the deserialized bytes from the buffer.
|
||||
* This method invokes the ns3::Chunk::DeserializeFrom method.
|
||||
*
|
||||
* \param trailer a reference to the trailer to remove from the internal buffer.
|
||||
* \returns the number of bytes removed from the end of the packet.
|
||||
@@ -254,12 +255,50 @@ public:
|
||||
*/
|
||||
uint32_t GetUid (void) const;
|
||||
|
||||
/**
|
||||
* \param os output stream in which the data should be printed.
|
||||
*
|
||||
* Iterate over the headers and trailers present in this packet,
|
||||
* from the first header to the last trailer and invoke, for
|
||||
* each of them, the user-provided method Header::DoPrint or
|
||||
* Trailer::DoPrint methods.
|
||||
*/
|
||||
void Print (std::ostream &os) const;
|
||||
/**
|
||||
* \param os output stream in which the data should be printed.
|
||||
* \param printer the output formatter to use to print
|
||||
* the content of this packet.
|
||||
*
|
||||
* Iterate over the headers and trailers present in this packet,
|
||||
* either in the "forward" (first header to last trailer) or in
|
||||
* the "backward" (last trailer to first header) direction, as
|
||||
* specified by the PacketPrinter::PrintForward or the
|
||||
* PacketPrinter::PrintBackward methods. For each header, trailer,
|
||||
* or fragment of a header or a trailer, invoke the user-specified
|
||||
* print callback stored in the specified PacketPrinter.
|
||||
*/
|
||||
void Print (std::ostream &os, const PacketPrinter &printer) const;
|
||||
|
||||
/**
|
||||
* By default, packets do not keep around enough metadata to
|
||||
* perform the operations requested by the Print methods. If you
|
||||
* want to be able to invoke any of the two ::Print methods,
|
||||
* you need to invoke this method at least once during the
|
||||
* simulation setup and before any packet is created.
|
||||
*
|
||||
* The packet metadata is also used to perform extensive
|
||||
* sanity checks at runtime when performing operations on a
|
||||
* Packet. For example, this metadata is used to verify that
|
||||
* when you remove a header from a packet, this same header
|
||||
* was actually present at the front of the packet. These
|
||||
* errors will be detected and will abort the program.
|
||||
*/
|
||||
static void EnableMetadata (void);
|
||||
private:
|
||||
Packet (Buffer buffer, Tags tags, uint32_t uid);
|
||||
Packet (Buffer buffer, Tags tags, PacketMetadata metadata);
|
||||
Buffer m_buffer;
|
||||
Tags m_tags;
|
||||
uint32_t m_uid;
|
||||
PacketMetadata m_metadata;
|
||||
static uint32_t m_globalUid;
|
||||
};
|
||||
|
||||
@@ -282,6 +321,7 @@ Packet::AddHeader (T const &header)
|
||||
uint32_t size = header.GetSize ();
|
||||
m_buffer.AddAtStart (size);
|
||||
header.Serialize (m_buffer.Begin ());
|
||||
m_metadata.AddHeader (header, size);
|
||||
}
|
||||
template <typename T>
|
||||
uint32_t
|
||||
@@ -291,6 +331,7 @@ Packet::RemoveHeader (T &header)
|
||||
"Must pass Header subclass to Packet::RemoveHeader");
|
||||
uint32_t deserialized = header.Deserialize (m_buffer.Begin ());
|
||||
m_buffer.RemoveAtStart (deserialized);
|
||||
m_metadata.RemoveHeader (header, deserialized);
|
||||
return deserialized;
|
||||
}
|
||||
template <typename T>
|
||||
@@ -303,6 +344,7 @@ Packet::AddTrailer (T const &trailer)
|
||||
m_buffer.AddAtEnd (size);
|
||||
Buffer::Iterator end = m_buffer.End ();
|
||||
trailer.Serialize (end);
|
||||
m_metadata.AddTrailer (trailer, size);
|
||||
}
|
||||
template <typename T>
|
||||
uint32_t
|
||||
@@ -312,6 +354,7 @@ Packet::RemoveTrailer (T &trailer)
|
||||
"Must pass Trailer subclass to Packet::RemoveTrailer");
|
||||
uint32_t deserialized = trailer.Deserialize (m_buffer.End ());
|
||||
m_buffer.RemoveAtEnd (deserialized);
|
||||
m_metadata.RemoveTrailer (trailer, deserialized);
|
||||
return deserialized;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,9 +67,26 @@ class Trailer : public Chunk {
|
||||
public:
|
||||
virtual ~Trailer ();
|
||||
private:
|
||||
/**
|
||||
* \returns a user-readable name to identify this type of header.
|
||||
*
|
||||
* The string returned is expected to be a single word with
|
||||
* all capital letters
|
||||
*/
|
||||
virtual std::string DoGetName (void) const = 0;
|
||||
/**
|
||||
* \param os the std output stream in which this
|
||||
* protocol trailer must print itself.
|
||||
*
|
||||
* Although the header is free to format its output as it
|
||||
* wishes, it is recommended to follow a few rules to integrate
|
||||
* with the packet pretty printer:
|
||||
* - start with flags, small field values located between a
|
||||
* pair of parens. Values should be separated by whitespace.
|
||||
* - follow the parens with the important fields, separated by
|
||||
* whitespace.
|
||||
* i.e.:
|
||||
* (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
|
||||
*/
|
||||
virtual void PrintTo (std::ostream &os) const = 0;
|
||||
|
||||
|
||||
@@ -10,9 +10,11 @@ def build(bld):
|
||||
common.uselib_local = ['ns3-core', 'ns3-simulator']
|
||||
common.source = [
|
||||
'buffer.cc',
|
||||
'header.cc',
|
||||
'chunk.cc',
|
||||
'header.cc',
|
||||
'trailer.cc',
|
||||
'packet-printer.cc',
|
||||
'packet-metadata.cc',
|
||||
'packet.cc',
|
||||
'tags.cc',
|
||||
'pcap-writer.cc',
|
||||
@@ -28,11 +30,13 @@ def build(bld):
|
||||
headers = bld.create_obj('ns3header')
|
||||
headers.source = [
|
||||
'buffer.h',
|
||||
'header.h',
|
||||
'chunk.h',
|
||||
'header.h',
|
||||
'trailer.h',
|
||||
'tags.h',
|
||||
'packet.h',
|
||||
'packet-printer.h',
|
||||
'packet-metadata.h',
|
||||
'uv-trace-source.h',
|
||||
'sv-trace-source.h',
|
||||
'fv-trace-source.h',
|
||||
|
||||
@@ -225,6 +225,7 @@ class CallbackBase {
|
||||
public:
|
||||
virtual ~CallbackBase () {}
|
||||
virtual CallbackImplBase *PeekImpl (void) const = 0;
|
||||
virtual Ptr<CallbackImplBase> GetImpl (void) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -278,7 +279,7 @@ public:
|
||||
: m_impl (impl)
|
||||
{}
|
||||
|
||||
bool IsNull (void) {
|
||||
bool IsNull (void) const {
|
||||
return (PeekImpl () == 0)?true:false;
|
||||
}
|
||||
void Nullify (void) {
|
||||
@@ -330,6 +331,19 @@ public:
|
||||
const Callback<R, T1,T2,T3,T4,T5> *goodType = static_cast<const Callback<R,T1,T2,T3,T4,T5> *> (&other);
|
||||
*this = *goodType;
|
||||
}
|
||||
void Assign (Ptr<CallbackImplBase> other) {
|
||||
CallbackImpl<R,T1,T2,T3,T4,T5> *impl = dynamic_cast<CallbackImpl<R,T1,T2,T3,T4,T5> *> (PeekPointer (other));
|
||||
if (other == 0)
|
||||
{
|
||||
NS_FATAL_ERROR ("Incompatible types. (feed to \"c++filt -t\")"
|
||||
" got=" << typeid (other).name () <<
|
||||
", expected=" << typeid (*impl).name ());
|
||||
}
|
||||
*this = Callback<R,T1,T2,T3,T4,T5> (impl);
|
||||
}
|
||||
virtual Ptr<CallbackImplBase>GetImpl (void) const {
|
||||
return m_impl;
|
||||
}
|
||||
private:
|
||||
virtual CallbackImpl<R,T1,T2,T3,T4,T5> *PeekImpl (void) const {
|
||||
return PeekPointer (m_impl);
|
||||
|
||||
@@ -83,24 +83,36 @@ ArpHeader::GetDestinationIpv4Address (void)
|
||||
return m_ipv4Dest;
|
||||
}
|
||||
|
||||
std::string
|
||||
ArpHeader::DoGetName (void) const
|
||||
{
|
||||
return "ARP";
|
||||
}
|
||||
|
||||
void
|
||||
ArpHeader::PrintTo (std::ostream &os) const
|
||||
{
|
||||
os << "(arp)";
|
||||
if (IsRequest ())
|
||||
{
|
||||
os << " source mac: " << m_macSource
|
||||
<< " source ipv4: " << m_ipv4Source
|
||||
<< " dest ipv4: " << m_ipv4Dest;
|
||||
os << "("
|
||||
<< "request "
|
||||
<< "source mac: " << m_macSource << " "
|
||||
<< "source ipv4: " << m_ipv4Source << " "
|
||||
<< "dest ipv4: " << m_ipv4Dest
|
||||
<< ")"
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ASSERT (IsReply ());
|
||||
os << " source mac: " << m_macSource
|
||||
<< " source ipv4: " << m_ipv4Source
|
||||
<< " dest mac: " << m_macDest
|
||||
<< " dest ipv4: " <<m_ipv4Dest;
|
||||
os << "("
|
||||
<< "reply "
|
||||
<< "source mac: " << m_macSource << " "
|
||||
<< "source ipv4: " << m_ipv4Source << " "
|
||||
<< "dest mac: " << m_macDest << " "
|
||||
<< "dest ipv4: " <<m_ipv4Dest
|
||||
<< ")"
|
||||
;
|
||||
}
|
||||
}
|
||||
uint32_t
|
||||
|
||||
@@ -50,6 +50,7 @@ class ArpHeader : public Header {
|
||||
Ipv4Address GetDestinationIpv4Address (void);
|
||||
|
||||
private:
|
||||
virtual std::string DoGetName (void) const;
|
||||
/**
|
||||
* \param os
|
||||
*/
|
||||
|
||||
@@ -46,12 +46,14 @@ AsciiTrace::~AsciiTrace ()
|
||||
void
|
||||
AsciiTrace::TraceAllQueues (void)
|
||||
{
|
||||
Packet::EnableMetadata ();
|
||||
TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/queue/*",
|
||||
MakeCallback (&AsciiTrace::LogDevQueue, this));
|
||||
}
|
||||
void
|
||||
AsciiTrace::TraceAllNetDeviceRx (void)
|
||||
{
|
||||
Packet::EnableMetadata ();
|
||||
TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/rx",
|
||||
MakeCallback (&AsciiTrace::LogDevRx, this));
|
||||
}
|
||||
@@ -115,7 +117,7 @@ AsciiTrace::LogDevQueue (TraceContext const &context, Packet const &packet)
|
||||
context.Get (interfaceIndex);
|
||||
m_os << "interface=" << interfaceIndex << " ";
|
||||
m_os << "pkt-uid=" << packet.GetUid () << " ";
|
||||
PrintType (packet);
|
||||
packet.Print (m_os);
|
||||
m_os << std::endl;
|
||||
}
|
||||
void
|
||||
@@ -129,7 +131,7 @@ AsciiTrace::LogDevRx (TraceContext const &context, Packet &p)
|
||||
context.Get (interfaceIndex);
|
||||
m_os << "interface=" << interfaceIndex << " ";
|
||||
m_os << "pkt-uid=" << p.GetUid () << " ";
|
||||
PrintType (p);
|
||||
p.Print (m_os);
|
||||
m_os << std::endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,17 +28,6 @@ NS_DEBUG_COMPONENT_DEFINE ("Ipv4Header");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
static uint16_t
|
||||
UtilsNtoh16 (uint16_t v)
|
||||
{
|
||||
uint16_t val;
|
||||
uint8_t *array;
|
||||
array = (uint8_t *)&v;
|
||||
val = (array[0] << 8) | (array[1] << 0);
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
bool Ipv4Header::m_calcChecksum = false;
|
||||
|
||||
Ipv4Header::Ipv4Header ()
|
||||
@@ -190,21 +179,48 @@ Ipv4Header::IsChecksumOk (void) const
|
||||
return m_goodChecksum;
|
||||
}
|
||||
|
||||
std::string
|
||||
Ipv4Header::DoGetName (void) const
|
||||
{
|
||||
return "IPV4";
|
||||
}
|
||||
|
||||
void
|
||||
Ipv4Header::PrintTo (std::ostream &os) const
|
||||
{
|
||||
// ipv4, right ?
|
||||
os << "(ipv4)"
|
||||
<< " tos=" << (uint32_t)m_tos
|
||||
<< ", payload length=" << UtilsNtoh16 (m_payloadSize)
|
||||
<< ", id=" << m_identification
|
||||
<< ", " << (IsLastFragment ()?"last":"more")
|
||||
<< ", " << (IsDontFragment ()?"dont":"may")
|
||||
<< ", frag offset=" << m_fragmentOffset
|
||||
<< ", ttl=" << m_ttl
|
||||
<< ", protocol=" << m_protocol
|
||||
<< ", source=" << m_source
|
||||
<< ", destination=" << m_destination;
|
||||
std::string flags;
|
||||
if (m_flags == 0)
|
||||
{
|
||||
flags = "none";
|
||||
}
|
||||
else if (m_flags & MORE_FRAGMENTS &&
|
||||
m_flags & DONT_FRAGMENT)
|
||||
{
|
||||
flags = "MF|DF";
|
||||
}
|
||||
else if (m_flags & DONT_FRAGMENT)
|
||||
{
|
||||
flags = "DF";
|
||||
}
|
||||
else if (m_flags & MORE_FRAGMENTS)
|
||||
{
|
||||
flags = "MF";
|
||||
}
|
||||
else
|
||||
{
|
||||
flags = "XX";
|
||||
}
|
||||
os << "("
|
||||
<< "tos 0x" << std::hex << m_tos << std::dec << " "
|
||||
<< "ttl " << m_ttl << " "
|
||||
<< "id " << m_identification << " "
|
||||
<< "offset " << m_fragmentOffset << " "
|
||||
<< "flags [" << flags << "] "
|
||||
<< "length: " << (m_payloadSize + 5 * 4)
|
||||
<< ") "
|
||||
<< m_source << " > " << m_destination
|
||||
;
|
||||
}
|
||||
uint32_t
|
||||
Ipv4Header::GetSerializedSize (void) const
|
||||
|
||||
@@ -140,6 +140,7 @@ public:
|
||||
bool IsChecksumOk (void) const;
|
||||
|
||||
private:
|
||||
virtual std::string DoGetName (void) const;
|
||||
virtual void PrintTo (std::ostream &os) const;
|
||||
virtual uint32_t GetSerializedSize (void) const;
|
||||
virtual void SerializeTo (Buffer::Iterator start) const;
|
||||
|
||||
@@ -91,15 +91,20 @@ UdpHeader::InitializeChecksum (Ipv4Address source,
|
||||
m_initialChecksum = Ipv4ChecksumCalculate (0, buf, 12);
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
UdpHeader::DoGetName (void) const
|
||||
{
|
||||
return "UDP";
|
||||
}
|
||||
|
||||
void
|
||||
UdpHeader::PrintTo (std::ostream &os) const
|
||||
{
|
||||
os << "(udp)"
|
||||
<< ", port source=" << m_sourcePort
|
||||
<< ", port destination=" << m_destinationPort
|
||||
<< ", length=" << m_payloadSize;
|
||||
os << "("
|
||||
<< "length: " << m_payloadSize + GetSize ()
|
||||
<< ") "
|
||||
<< m_sourcePort << " > " << m_destinationPort
|
||||
;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
||||
@@ -81,6 +81,7 @@ public:
|
||||
uint8_t protocol);
|
||||
|
||||
private:
|
||||
virtual std::string DoGetName (void) const;
|
||||
virtual void PrintTo (std::ostream &os) const;
|
||||
virtual uint32_t GetSerializedSize (void) const;
|
||||
virtual void SerializeTo (Buffer::Iterator start) const;
|
||||
|
||||
@@ -47,14 +47,20 @@ LlcSnapHeader::GetSerializedSize (void) const
|
||||
return 1 + 1 + 1 + 3 + 2;
|
||||
}
|
||||
|
||||
std::string
|
||||
LlcSnapHeader::DoGetName (void) const
|
||||
{
|
||||
return "LLCSNAP";
|
||||
}
|
||||
|
||||
void
|
||||
LlcSnapHeader::PrintTo (std::ostream &os) const
|
||||
{
|
||||
os << "(mac)"
|
||||
<< " EtherType: ";
|
||||
os << "(type 0x";
|
||||
os.setf (std::ios::hex, std::ios::basefield);
|
||||
os << m_etherType;
|
||||
os.setf (std::ios::dec, std::ios::basefield);
|
||||
os << ")";
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -37,6 +37,7 @@ class LlcSnapHeader : public Header {
|
||||
uint16_t GetType (void);
|
||||
|
||||
private:
|
||||
virtual std::string DoGetName (void) const;
|
||||
virtual void PrintTo (std::ostream &os) const;
|
||||
virtual uint32_t GetSerializedSize (void) const;
|
||||
virtual void SerializeTo (Buffer::Iterator start) const;
|
||||
|
||||
@@ -18,97 +18,168 @@
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "ns3/wall-clock-ms.h"
|
||||
#include "ns3/system-wall-clock-ms.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/chunk-constant-data.h"
|
||||
#include "ns3/chunk-udp.h"
|
||||
#include "ns3/chunk-ipv4.h"
|
||||
#include "ns3/packet-metadata.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
template <int N>
|
||||
class BenchHeader : public Header
|
||||
{
|
||||
public:
|
||||
BenchHeader ();
|
||||
bool IsOk (void) const;
|
||||
private:
|
||||
virtual std::string DoGetName (void) const;
|
||||
virtual void PrintTo (std::ostream &os) const;
|
||||
virtual uint32_t GetSerializedSize (void) const;
|
||||
virtual void SerializeTo (Buffer::Iterator start) const;
|
||||
virtual uint32_t DeserializeFrom (Buffer::Iterator start);
|
||||
bool m_ok;
|
||||
};
|
||||
|
||||
template <int N>
|
||||
BenchHeader<N>::BenchHeader ()
|
||||
: m_ok (false)
|
||||
{}
|
||||
|
||||
template <int N>
|
||||
bool
|
||||
BenchHeader<N>::IsOk (void) const
|
||||
{
|
||||
return m_ok;
|
||||
}
|
||||
|
||||
template <int N>
|
||||
std::string
|
||||
BenchHeader<N>::DoGetName (void) const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << N;
|
||||
return oss.str ();
|
||||
}
|
||||
|
||||
template <int N>
|
||||
void
|
||||
BenchHeader<N>::PrintTo (std::ostream &os) const
|
||||
{
|
||||
NS_ASSERT (false);
|
||||
}
|
||||
template <int N>
|
||||
uint32_t
|
||||
BenchHeader<N>::GetSerializedSize (void) const
|
||||
{
|
||||
return N;
|
||||
}
|
||||
template <int N>
|
||||
void
|
||||
BenchHeader<N>::SerializeTo (Buffer::Iterator start) const
|
||||
{
|
||||
start.WriteU8 (N, N);
|
||||
}
|
||||
template <int N>
|
||||
uint32_t
|
||||
BenchHeader<N>::DeserializeFrom (Buffer::Iterator start)
|
||||
{
|
||||
m_ok = true;
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
if (start.ReadU8 () != N)
|
||||
{
|
||||
m_ok = false;
|
||||
}
|
||||
}
|
||||
return N;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
benchPtrA (uint32_t n)
|
||||
{
|
||||
ChunkConstantData data = ChunkConstantData (2000, 1);
|
||||
ChunkUdp udp;
|
||||
ChunkIpv4 ipv4;
|
||||
BenchHeader<25> ipv4;
|
||||
BenchHeader<8> udp;
|
||||
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
Packet p;
|
||||
p.add (&data);
|
||||
p.add (&udp);
|
||||
p.add (&ipv4);
|
||||
Packet p (2000);
|
||||
p.AddHeader (udp);
|
||||
p.AddHeader (ipv4);
|
||||
Packet o = p;
|
||||
o.peek (&ipv4);
|
||||
o.remove (&ipv4);
|
||||
o.peek (&udp);
|
||||
o.remove (&udp);
|
||||
o.peek (&data);
|
||||
o.remove (&data);
|
||||
o.RemoveHeader (ipv4);
|
||||
o.RemoveHeader (udp);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
benchPtrB (uint32_t n)
|
||||
{
|
||||
ChunkConstantData data = ChunkConstantData (2000, 1);
|
||||
ChunkUdp udp;
|
||||
ChunkIpv4 ipv4;
|
||||
BenchHeader<25> ipv4;
|
||||
BenchHeader<8> udp;
|
||||
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
Packet p;
|
||||
p.add (&data);
|
||||
p.add (&udp);
|
||||
p.add (&ipv4);
|
||||
Packet p (2000);
|
||||
p.AddHeader (udp);
|
||||
p.AddHeader (ipv4);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ptrC2 (Packet p)
|
||||
{
|
||||
ChunkConstantData data = ChunkConstantData (2000, 1);
|
||||
ChunkUdp udp;
|
||||
BenchHeader<8> udp;
|
||||
|
||||
p.peek (&udp);
|
||||
p.remove (&udp);
|
||||
p.peek (&data);
|
||||
p.remove (&data);
|
||||
p.RemoveHeader (udp);
|
||||
}
|
||||
|
||||
static void
|
||||
ptrC1 (Packet p)
|
||||
{
|
||||
ChunkIpv4 ipv4;
|
||||
p.peek (&ipv4);
|
||||
p.remove (&ipv4);
|
||||
BenchHeader<25> ipv4;
|
||||
p.RemoveHeader (ipv4);
|
||||
ptrC2 (p);
|
||||
}
|
||||
|
||||
static void
|
||||
benchPtrC (uint32_t n)
|
||||
{
|
||||
ChunkConstantData data = ChunkConstantData (2000, 1);
|
||||
ChunkUdp udp;
|
||||
ChunkIpv4 ipv4;
|
||||
BenchHeader<25> ipv4;
|
||||
BenchHeader<8> udp;
|
||||
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
Packet p;
|
||||
p.add (&data);
|
||||
p.add (&udp);
|
||||
p.add (&ipv4);
|
||||
Packet p (2000);
|
||||
p.AddHeader (udp);
|
||||
p.AddHeader (ipv4);
|
||||
ptrC1 (p);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
benchPrint (uint32_t n)
|
||||
{
|
||||
PacketPrinter printer;
|
||||
BenchHeader<25> ipv4;
|
||||
BenchHeader<8> udp;
|
||||
Packet p (2000);
|
||||
p.AddHeader (udp);
|
||||
p.AddHeader (ipv4);
|
||||
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
{
|
||||
p.Print (std::cerr, printer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
runBench (void (*bench) (uint32_t), uint32_t n, char const *name)
|
||||
{
|
||||
WallClockMs time;
|
||||
time.start ();
|
||||
SystemWallClockMs time;
|
||||
time.Start ();
|
||||
(*bench) (n);
|
||||
unsigned long long deltaMs = time.end ();
|
||||
unsigned long long deltaMs = time.End ();
|
||||
double ps = n;
|
||||
ps *= 1000;
|
||||
ps /= deltaMs;
|
||||
@@ -119,17 +190,31 @@ int main (int argc, char *argv[])
|
||||
{
|
||||
uint32_t n = 0;
|
||||
while (argc > 0) {
|
||||
if (strncmp ("--n=", argv[0],strlen ("--n=")) == 0) {
|
||||
if (strncmp ("--n=", argv[0],strlen ("--n=")) == 0)
|
||||
{
|
||||
char const *nAscii = argv[0] + strlen ("--n=");
|
||||
n = atoi (nAscii);
|
||||
}
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
|
||||
runBench (&benchPtrA, n, "a");
|
||||
runBench (&benchPtrB, n, "b");
|
||||
runBench (&benchPtrC, n, "c");
|
||||
|
||||
Packet::EnableMetadata ();
|
||||
runBench (&benchPrint, n, "print");
|
||||
PacketMetadata::SetOptOne (false);
|
||||
runBench (&benchPtrA, n, "meta-a");
|
||||
runBench (&benchPtrB, n, "meta-b");
|
||||
runBench (&benchPtrC, n, "meta-c");
|
||||
PacketMetadata::SetOptOne (true);
|
||||
runBench (&benchPtrA, n, "meta-a-opt");
|
||||
runBench (&benchPtrB, n, "meta-b-opt");
|
||||
runBench (&benchPtrC, n, "meta-c-opt");
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user