[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This section describes how to create and use the ns3::Packet
object.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The following command will create a new packet with a new unique Id.
Ptr<Packet> pkt = Create<Packet> ();
What is the Uid (unique Id)? It is an internal id that the system uses to identify packets. It can be fetched via the following method:
uint32_t uid = pkt->GetUid ();
But please note the following. This uid is an internal uid and cannot be counted on to provide an accurate counter of how many "simulated packets" of a particular protocol are in the system. It is not trivial to make this uid into such a counter, because of questions such as what should the uid be when the packet is sent over broadcast media, or when fragmentation occurs. If a user wants to trace actual packet counts, he or she should look at e.g. the IP ID field or transport sequence numbers, or other packet or frame counters at other protocol layers.
We mentioned above that it is possible to create packets with zero-filled payloads that do not actually require a memory allocation (i.e., the packet may behave, when delays such as serialization or transmission delays are computed, to have a certain number of payload bytes, but the bytes will only be allocated on-demand when needed). The command to do this is, when the packet is created:
Ptr<Packet> pkt = Create<Packet> (N);
where N is a positive integer.
The packet now has a size of N bytes, which can be verified by the GetSize() method:
/** * \returns the size in bytes of the packet (including the zero-filled * initial payload) */ uint32_t GetSize (void) const;
You can also initialize a packet with a character buffer. The input data is copied and the input buffer is untouched. The constructor applied is:
Packet (uint8_t const *buffer, uint32_t size);
Here is an example:
|
Packets are freed when there are no more references to them, as with all ns-3 objects referenced by the Ptr class.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
After the initial packet creation (which may possibly create some fake initial bytes of payload), all subsequent buffer data is added by adding objects of class Header or class Trailer. Note that, even if you are in the application layer, handling packets, and want to write application data, you write it as an ns3::Header or ns3::Trailer. If you add a Header, it is prepended to the packet, and if you add a Trailer, it is added to the end of the packet. If you have no data in the packet, then it makes no difference whether you add a Header or Trailer. Since the APIs and classes for header and trailer are pretty much identical, we’ll just look at class Header here.
The first step is to create a new header class. All new Header classes must inherit from class Header, and implement the following methods:
Serialize ()
Deserialize ()
GetSerializedSize ()
Print ()
To see a simple example of how these are done, look at the UdpHeader class headers src/internet-stack/udp-header.cc. There are many other examples within the source code.
Once you have a header (or you have a preexisting header), the following Packet API can be used to add or remove such headers.
|
For instance, here are the typical operations to add and remove a UDP header.
|
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
There is a single base class of Tag that all packet tags must derive from. They are used in two different tag lists in the packet; the lists have different semantics and different expected use cases.
As the names imply, ByteTags follow bytes and PacketTags follow packets. What this means is that when operations are done on packets, such as fragmentation, concatenation, and appending or removing headers, the byte tags keep track of which packet bytes they cover. For instance, if a user creates a TCP segment, and applies a ByteTag to the segment, each byte of the TCP segment will be tagged. However, if the next layer down inserts an IPv4 header, this ByteTag will not cover those bytes. The converse is true for the PacketTag; it covers a packet despite the operations on it.
PacketTags are limited in size to 20 bytes. This is a modifiable
compile-time constant in src/common/packet-tag-list.h
. ByteTags
have no such restriction.
Each tag type must subclass ns3::Tag
, and only one instance of
each Tag type may be in each tag list. Here are a few differences
in the behavior of packet tags and byte tags.
As of ns-3.5, Tags are not serialized and deserialized to a buffer when
Packet::Serialize ()
and Packet::Deserialize ()
are called;
this is an open bug.
If a user wants to take an existing packet object and reuse it as a new packet, he or she should remove all byte tags and packet tags before doing so. An example is the UdpEchoServer class, which takes the received packet and "turns it around" to send back to the echo client.
The Packet API for byte tags is given below.
|
The Packet API for packet tags is given below.
|
Here is a simple example illustrating the use of tags from the
code in src/internet-stack/udp-socket-impl.cc
:
Ptr<Packet> p; // pointer to a pre-existing packet SocketIpTtlTag tag tag.SetTtl (m_ipMulticastTtl); // Convey the TTL from UDP layer to IP layer p->AddPacketTag (tag);
This tag is read at the IP layer, then stripped (src/internet-stack/ipv4-l3-protocol.cc
:
uint8_t ttl = m_defaultTtl; SocketIpTtlTag tag; bool found = packet->RemovePacketTag (tag); if (found) { ttl = tag.GetTtl (); }
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Packets may be fragmented or merged together. For example, to
fragment a packet p
of 90 bytes into two packets, one containing
the first 10 bytes and the other containing the remaining 80, one may call the
following code:
Ptr<Packet> frag0 = p->CreateFragment (0, 10); Ptr<Packet> frag1 = p->CreateFragment (10, 90);
As discussed above, the packet tags from p
will follow to both
packet fragments, and the byte tags will follow the byte ranges as needed.
Now, to put them back together:
frag0->AddAtEnd (frag1);
Now frag0 should be equivalent to the original packet p
. If,
however, there were operations on the fragments before being reassembled
(such as tag operations or header operations), the new packet will not
be the same.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
We mentioned above that packets, being on-the-wire representations of byte buffers, present a problem to print out in a structured way unless the printing function has access to the context of the header. For instance, consider a tcpdump-like printer that wants to pretty-print the contents of a packet.
To enable this usage, packets may have metadata enabled (disabled by
default for performance reasons). This class is used by the Packet
class to record every operation performed on the packet’s buffer, and
provides an implementation of Packet::Print ()
method that uses
the metadata to analyze the content of the packet’s buffer.
The 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.
To enable this operation, users will typically insert one or both of these statements at the beginning of their programs:
Packet::EnablePrinting (); Packet::EnableChecking ();
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] |
This document was generated on April 21, 2010 using texi2html 1.82.