[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

11.2 Using the packet interface

This section describes how to create and use the ns3::Packet object.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

11.2.1 Creating a new packet

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:

 
 
  Ptr<Packet> pkt1 = Create<Packet> (reinterpret_cast<const uint8_t*> ("hello"), 5);

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] [ ? ]

11.2.2 Adding and removing Buffer data

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:

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.

 
 
  /**
   * Add header to this packet. This method invokes the
   * Header::GetSerializedSize and Header::Serialize
   * methods to reserve space in the buffer and request the 
   * header to serialize itself in the packet buffer.
   *
   * \param header a reference to the header to add to this packet.
   */
  void AddHeader (const Header & header);
  /**
   * Deserialize and remove the header from the internal buffer.
   * This method invokes Header::Deserialize.
   *
   * \param header a reference to the header to remove from the internal buffer.
   * \returns the number of bytes removed from the packet.
   */
  uint32_t RemoveHeader (Header &header);
  /**
   * Deserialize but does _not_ remove the header from the internal buffer.
   * This method invokes Header::Deserialize.
   *
   * \param header a reference to the header to read from the internal buffer.
   * \returns the number of bytes read from the packet.
   */
  uint32_t PeekHeader (Header &header) const;

For instance, here are the typical operations to add and remove a UDP header.

 
 
 // add header
 Ptr<Packet> packet = Create<Packet> ();
 UdpHeader udpHeader;
 // Fill out udpHeader fields appropriately
 packet->AddHeader (udpHeader);
 ...
 // remove header
 UdpHeader udpHeader;
 packet->RemoveHeader (udpHeader); 
 // Read udpHeader fields as needed

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

11.2.3 Adding and removing Tags

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.

 
 
  /**
   * \param tag the new tag to add to this packet
   *
   * Tag each byte included in this packet with the
   * new tag.
   *
   * Note that adding a tag is a const operation which is pretty 
   * un-intuitive. The rationale is that the content and behavior of
   * a packet is _not_ changed when a tag is added to a packet: any
   * code which was not aware of the new tag is going to work just
   * the same if the new tag is added. The real reason why adding a
   * tag was made a const operation is to allow a trace sink which gets
   * a packet to tag the packet, even if the packet is const (and most
   * trace sources should use const packets because it would be
   * totally evil to allow a trace sink to modify the content of a
   * packet).
   */
  void AddByteTag (const Tag &tag) const;
  /**
   * \returns an iterator over the set of byte tags included in this packet.
   */
  ByteTagIterator GetByteTagIterator (void) const;
  /**
   * \param tag the tag to search in this packet
   * \returns true if the requested tag type was found, false otherwise.
   *
   * If the requested tag type is found, it is copied in the user's 
   * provided tag instance.
   */
  bool FindFirstMatchingByteTag (Tag &tag) const;
  
  /**
   * Remove all the tags stored in this packet.
   */
  void RemoveAllByteTags (void);

  /**
   * \param os output stream in which the data should be printed.
   *
   * Iterate over the tags present in this packet, and
   * invoke the Print method of each tag stored in the packet.
   */
  void PrintByteTags (std::ostream &os) const;

The Packet API for packet tags is given below.

 
 
  /**
   * \param tag the tag to store in this packet
   *
   * Add a tag to this packet. This method calls the
   * Tag::GetSerializedSize and, then, Tag::Serialize.
   *
   * Note that this method is const, that is, it does not
   * modify the state of this packet, which is fairly
   * un-intuitive.
   */
  void AddPacketTag (const Tag &tag) const;
  /**
   * \param tag the tag to remove from this packet
   * \returns true if the requested tag is found, false
   *          otherwise.
   *
   * Remove a tag from this packet. This method calls
   * Tag::Deserialize if the tag is found.
   */
  bool RemovePacketTag (Tag &tag);
  /**
   * \param tag the tag to search in this packet
   * \returns true if the requested tag is found, false
   *          otherwise.
   *
   * Search a matching tag and call Tag::Deserialize if it is found.
   */
  bool PeekPacketTag (Tag &tag) const;
  /**
   * Remove all packet tags.
   */
  void RemoveAllPacketTags (void);
  
  /**
   * \param os the stream in which we want to print data.
   *
   * Print the list of 'packet' tags.
   *
   * \sa Packet::AddPacketTag, Packet::RemovePacketTag, Packet::PeekPacketTag,
   *  Packet::RemoveAllPacketTags
   */
  void PrintPacketTags (std::ostream &os) const;
  
  /**
   * \returns an object which can be used to iterate over the list of
   *  packet tags.
   */
  PacketTagIterator GetPacketTagIterator (void) const;

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] [ ? ]

11.2.4 Fragmentation and concatenation

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] [ ? ]

11.2.5 Enabling metadata

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 August 20, 2010 using texi2html 1.82.