update manual for new tag API
authorTom Henderson <tomh@tomh.org>
Mon, 08 Jun 2009 09:22:29 +0200
changeset 4506 5e742340ef51
parent 4505 e865dbc1d157
child 4507 7b4adb81e21e
update manual for new tag API
doc/manual/figures/packet.dia
doc/manual/packets.texi
Binary file doc/manual/figures/packet.dia has changed
--- a/doc/manual/packets.texi	Mon Jun 08 09:19:00 2009 +0200
+++ b/doc/manual/packets.texi	Mon Jun 08 09:22:29 2009 +0200
@@ -15,11 +15,14 @@
 emulated applications
 @end itemize
 
-@emph{ns} Packet objects contain a buffer of bytes: protocol headers and
-trailers are serialized in this buffer of bytes using user-provided
-serialization and deserialization routines. The content of this byte
-buffer is expected to match bit-for-bit the content of a real packet on
-a real network implementing the protocol of interest.
+Each network packet contains a byte buffer, a set of byte tags, a set of
+packet tags, and metadata.
+
+The byte buffer stores the serialized content of the headers and trailers 
+added to a packet. The serialized representation of these headers is expected
+to match that of real network packets bit for bit (although nothing
+forces you to do this) which means that the content of a packet buffer
+is expected to be that of a real packet.
 
 Fragmentation and defragmentation are quite natural to implement within
 this context: since we have a buffer of real bytes, we can split it in
@@ -29,19 +32,37 @@
 the simulator. We also expect that performing a real-time plug of the
 simulator to a real-world network will be easy.
 
-Because we understand that simulation developers often wish to store in
-packet objects data which is not found in the real packets (such as
-timestamps or any kind of similar in-band data), the @emph{ns} Packet class
-can also store extra per-packet "Tags" which are 16 bytes blobs of data.
-Any Packet can store any number of unique Tags, each of which is
-uniquely identified by its C++ type. These tags make it easy to attach
-per-model data to a packet without having to patch the main Packet
-class or Packet facilities.
+One problem  that this design choice raises is that it is difficult to
+pretty-print the packet headers without context.  The packet metadata 
+describes the type of the headers and trailers which
+were serialized in the byte buffer. The maintenance of metadata is
+optional and disabled by default. To enable it, you must call
+Packet::EnableMetadata() and this will allow you to get non-empty
+output from Packet::Print and Packet::Print.
 
+Also, developers often want to store data in packet objects that is not found
+in the real packets (such as timestamps or flow-ids).  The Packet class
+deals with this requirement by storing a set of tags (class Tag).  
+We have found two classes of use cases for these tags, which leads to
+two different types of tags.  So-called
+'byte' tags are used to tag a subset of the bytes in the packet byte buffer
+while 'packet' tags are used to tag the packet itself. The main difference
+between these two kinds of tags is what happens when packets are copied,
+fragmented, and reassembled: 'byte' tags follow bytes while 'packet' tags
+follow packets. Another important difference between these two kinds of tags
+is that byte tags cannot be removed and are expected to be written once,
+and read many times, while packet tags are expected to be written once,
+read many times, and removed exactly once. An example of a 'byte' 
+tag is a FlowIdTag which contains a flow id and is set by the application
+generating traffic. An example of a 'packet' tag is a cross-layer 
+QoS class id set by an application and processed by a lower-level MAC 
+layer.
+ 
 Memory management of Packet objects is entirely automatic and extremely
 efficient: memory for the application-level payload can be modelized by
 a virtual buffer of zero-filled bytes for which memory is never allocated
-unless explicitely requested by the user or unless the packet is fragmented.
+unless explicitly requested by the user or unless the packet is fragmented
+or serialized out to a real network device.
 Furthermore, copying, adding, and, removing headers or trailers to a packet
 has been optimized to be virtually free through a technique known as
 Copy On Write.
@@ -54,32 +75,12 @@
 tension between ease-of-use, performance, and safe interface
 design. 
 
-There are a few requirements on this object design:
-@itemize @bullet 
-@item Creation, management, and deletion of this object
-should be as simple as possible, while avoiding the
-chance for memory leaks and/or heap corruption; 
-@item Packets should support serialization and deserialization
-so that network emulation is supported;
-@item Packets should support fragmentation and concatenation
-(multiple packets in a data link frame), especially for wireless
-support;
-@item It should be natural for packets to carry actual application
-data, or if there is only an emulated application and there is
-no need to carry dummy bytes, smaller packets could be used with
-just the headers and a record of the payload size, but not actual
-application bytes, conveyed in the simulated packet.
-@item Packets should facilitate BSD-like operations on mbufs, for
-support of ported operating system stacks.
-@item Additional side-information should be supported, such as
-a tag for cross-layer information.
-@end itemize
-
 @section Packet design overview
 
 Unlike @emph{ns-2}, in which Packet objects contain a buffer of C++
 structures corresponding to protocol headers, each network packet in
-@emph{ns-3} contains a byte Buffer and a list of Tags:
+@emph{ns-3} contains a byte Buffer, a list of byte Tags, a list of
+packet Tags, and a PacketMetadata object:
 @itemize @bullet
 @item The byte buffer stores the serialized content of the chunks 
 added to a packet. The serialized representation of these chunks is 
@@ -88,16 +89,12 @@
 of a packet buffer is expected to be that of a real packet.
 Packets can also be created with an arbitrary zero-filled payload
 for which no real memory is allocated.
-@item The list of tags stores an arbitrarily large set of arbitrary 
+@item Each list of tags stores an arbitrarily large set of arbitrary 
 user-provided data structures in the packet.  Each Tag is uniquely
 identified by its type; only one instance of each 
 type of data structure is allowed in a list of tags. These tags typically 
 contain per-packet cross-layer information or flow identifiers (i.e.,
-things that you wouldn't find in the bits on the wire). Each tag 
-stored in the tag list can be at most 16 bytes.
-Trying to attach bigger data structures will trigger 
-crashes at runtime.  The 16 byte limit is a modifiable compilation
-constant.
+things that you wouldn't find in the bits on the wire). 
 @end itemize
 
 @float Figure,fig:packets
@@ -110,17 +107,29 @@
 is provided later in Figure @ref{fig:buffer}.
 In \nsthree, the Packet byte buffer is analogous to a Linux skbuff
 or BSD mbuf; it is a serialized representation of the actual
-data in the packet.  The tag list is a container for extra
+data in the packet.  The tag lists are containers for extra
 items useful for simulation convenience; if a Packet is converted
 to an emulated packet and put over an actual network, the tags
 are stripped off and the byte buffer is copied directly
 into a real packet.
 
-The Packet class has value semantics:  it can be freely copied around,
-allocated on the stack, and passed to functions as arguments.  Whenever
-an instance is copied, the full underlying data is not copied; it
-has ``copy-on-write'' (COW) semantics.  Packet instances can be passed
-by value to function arguments without any performance hit.
+Packets are reference counted objects.  They are handled with smart
+pointer (Ptr) objects like many of the objects in the ns-3 system.
+One small difference you will see is that class Packet does not
+inherit from class Object or class RefCountBase, and implements the
+Ref() and Unref() methods directly.  This was designed to avoid the overhead
+of a vtable in class Packet.
+
+The Packet class is designed to be copied cheaply; the overall design
+is based on Copy on Write (COW).  When there are multiple references
+to a packet object, and there is an operation on one of them, only 
+so-called "dirty" operations will trigger a deep copy of the packet:
+@itemize @bullet
+@item @code{ns3::Packet::AddHeader()}
+@item @code{ns3::Packet::AddTrailer()}
+@item @code{both versions of ns3::Packet::AddAtEnd()}
+@item @code{Packet::RemovePacketTag()}
+@end itemize
 
 The fundamental classes for adding to and removing from the byte
 buffer are @code{class Header} and @code{class Trailer}.  
@@ -149,78 +158,203 @@
 
 Similarly, user-defined Tags can be appended to the packet. 
 Unlike Headers, Tags are not serialized into a contiguous buffer
-but are stored in an array.  By default, Tags are limited to 16 bytes in
-size.  Tags can be flexibly defined to be any type, but there
+but are stored in lists.  Tags can be flexibly defined to be any 
+type, but there
 can only be one instance of any particular object type in
 the Tags buffer at any time.  
 
-@section Packet interface
+@section Using the packet interface
+
+This section describes how to create and use the @code{ns3::Packet} object.
+
+@subsection Creating a new packet
 
-The public member functions of a Packet object are as follows:
+The following command will create a new packet with a new unique
+Id.
 
-@subsection Constructors
+@verbatim
+  Ptr<Packet> pkt = Create<Packet> ();
+@end verbatim
+
+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:
 @verbatim
-    /**
-     * Create an empty packet with a new uid (as returned
-     * by getUid).
-     */
-    Packet ();
-    /**
-     * Create a packet with a zero-filled payload.
-     * The memory necessary for the payload is not allocated:
-     * it will be allocated at any later point if you attempt
-     * to fragment this packet or to access the zero-filled
-     * bytes. The packet is allocated with a new uid (as
-     * returned by getUid).
-     *
-     * \param size the size of the zero-filled payload
-     */
-    Packet (uint32_t size);
+  uint32_t uid = pkt->GetUid ();
+@end verbatim
+
+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:
+@verbatim
+  Ptr<Packet> pkt = Create<Packet> (N);
 @end verbatim
+where N is a positive integer.  
+
+The packet now has a size of N bytes, which can be verified by the GetSize()
+method:
+@verbatim
+  /**
+   * \returns the size in bytes of the packet (including the zero-filled
+   *          initial payload)
+   */
+  uint32_t GetSize (void) const;
+@end verbatim
+
+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:
+@verbatim
+  Packet (uint8_t const *buffer, uint32_t size);
+@end verbatim
+Here is an example:
+@verbatim
+  Ptr<Packet> pkt1 = Create<Packet> (reinterpret_cast<const uint8_t*> ("hello"), 5);
+@end verbatim
+
+Packets are freed when there are no more references to them, as with
+all ns-3 objects referenced by the Ptr class.
 
 @subsection Adding and removing Buffer data
-The below code is reproduced for Header class only; similar functions
-exist for Trailers.
+
+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:
+@itemize @bullet
+@item @code{Serialize ()}
+@item @code{Deserialize ()}
+@item @code{GetSerializedSize ()}
+@item @code{Print ()}
+@end itemize 
+
+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.
+
 @verbatim
-    /**
-     * Add header to this packet. This method invokes the
-     * ns3::Header::serializeTo method to request the header to serialize
-     * itself in the packet buffer.
-     *
-     * \param header a reference to the header to add to this packet.
-     */
-    void Add (Header const &header);
-    /**
-     * Deserialize header from this packet. This method invokes the
-     * ns3::Header::deserializeFrom method to request the header to deserialize
-     * itself from the packet buffer. This method does not remove
-     * the data from the buffer. It merely reads it.
-     *
-     * \param header a reference to the header to deserialize from the buffer
-     */
-    void Peek (Header &header);
-    /**
-     * Remove a deserialized header from the internal buffer.
-     * This method removes the bytes read by Packet::peek from
-     * the packet buffer.
-     *
-     * \param header a reference to the header to remove from the internal buffer.
-     */
-    void Remove (Header const &header);
-    /**
-     * Add trailer to this packet. This method invokes the
-     * ns3::Trailer::serializeTo method to request the trailer to serialize
-     * itself in the packet buffer.
-     *
-     * \param trailer a reference to the trailer to add to this packet.
-     */
+  /**
+   * 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;
+@end verbatim
+
+For instance, here are the typical operations to add and remove a UDP header.
+
+@verbatim
+ // 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
 @end verbatim
 
 @subsection Adding and removing Tags
 
-@strong{Note:  This part of ns-3 will change for ns-3.5; see this mail message:
-http://mailman.isi.edu/pipermail/ns-developers/2009-March/005557.html}
+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 @code{src/common/packet-tag-list.h}.  ByteTags
+have no such restriction.
 
+Each tag type must subclass @code{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.
+@itemize @bullet
+@item @strong{Fragmentation:}  As mentioned above, when a packet is fragmented,
+each packet fragment (which is a new packet) will get a copy of all packet
+tags, and byte tags will follow the new packet boundaries (i.e. if the
+fragmented packets fragment across a buffer region covered by the byte
+tag, both packet fragments will still have the appropriate buffer regions
+byte tagged).
+@item @strong{Concatenation:}  When packets are combined, two different
+buffer regions will become one.  For byte tags, the byte tags simply
+follow the respective buffer regions.  For packet tags, only the
+tags on the first packet survive the merge.
+@item @strong{Finding and Printing:}  Both classes allow you to iterate
+over all of the tags and print them.
+@item @strong{Removal:}  Users can add and remove the same packet tag
+multiple times on a single packet (AddPacketTag () and RemovePacketTag ()).  
+The packet However, once a byte tag is added,
+it can only be removed by stripping all byte tags from the packet.  
+Removing one of possibly multiple byte tags is not supported by the 
+current API.  
+@end itemize  
+
+As of ns-3.5, Tags are not serialized and deserialized to a buffer when
+@code{Packet::Serialize ()} and @code{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.
 @verbatim
   /**
    * \param tag the new tag to add to this packet
@@ -228,7 +362,7 @@
    * Tag each byte included in this packet with the
    * new tag.
    *
-   * Note that adding a tag is a const operation which is pretty
+   * 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
@@ -239,217 +373,160 @@
    * totally evil to allow a trace sink to modify the content of a
    * packet).
    */
-  void AddTag (const Tag &tag) const;
+  void AddByteTag (const Tag &tag) const;
   /**
-   * \returns an iterator over the set of tags included in this packet.
+   * \returns an iterator over the set of byte tags included in this packet.
    */
-  TagIterator GetTagIterator (void) const;
+  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
+   * If the requested tag type is found, it is copied in the user's 
    * provided tag instance.
    */
-  bool FindFirstMatchingTag (Tag &tag) const;
-
+  bool FindFirstMatchingByteTag (Tag &tag) const;
+  
   /**
    * Remove all the tags stored in this packet.
    */
-  void RemoveAllTags (void);
+  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;
 @end verbatim
 
-@subsection Fragmentation
+The Packet API for packet tags is given below.
 @verbatim
-    /**
-     * Create a new packet which contains a fragment of the original
-     * packet. The returned packet shares the same uid as this packet.
-     *
-     * \param start offset from start of packet to start of fragment to create
-     * \param length length of fragment to create
-     * \returns a fragment of the original packet
-     */
-    Packet CreateFragment (uint32_t start, uint32_t length) const;
-
-        /**
-         * Concatenate the input packet at the end of the current
-         * packet. This does not alter the uid of either packet.
-         * 
-         * \param packet packet to concatenate
-         */
-    void addAtEnd (Packet packet);
-
-        /oncatenate the input packet at the end of the current
-     * packet. This does not alter the uid of either packet.
-     *
-     * \param packet packet to concatenate
-     */
-    void AddAtEnd (Packet packet);
-    /**
-     * Concatenate the fragment of the input packet identified
-     * by the offset and size parameters at the end of the current
-     * packet. This does not alter the uid of either packet.
-     *
-     * \param packet to concatenate
-     * \param offset offset of fragment to copy from the start of the input packet
-     * \param size size of fragment of input packet to copy.
-     */
-    void AddAtEnd (Packet packet, uint32_t offset, uint32_t size);
-    /**
-     * Remove size bytes from the end of the current packet
-     * It is safe to remove more bytes that what is present in
-     * the packet.
-     *
-     * \param size number of bytes from remove
-     */
-    void RemoveAtEnd (uint32_t size);
-    /**
-     * Remove size bytes from the start of the current packet.
-     * It is safe to remove more bytes that what is present in
-     * the packet.
-     *
-     * \param size number of bytes from remove
-     */
-    void RemoveAtStart (uint32_t size);
-@end verbatim
-
-@subsection Miscellaneous
-@verbatim
-    /**
-     * \returns the size in bytes of the packet (including the zero-filled
-     *          initial payload)
-     */
-    uint32_t GetSize (void) const;
-    /**
-     * If you try to change the content of the buffer
-     * returned by this method, you will die.
-     *
-     * \returns a pointer to the internal buffer of the packet.
-     */
-    uint8_t const *PeekData (void) const;
-    /**
-     * A packet is allocated a new uid when it is created
-     * empty or with zero-filled payload.
-     *
-     * \returns an integer identifier which uniquely
-     *          identifies this packet.
-     */
-    uint32_t GetUid (void) const;
+  /**
+   * \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;
 @end verbatim
 
-@section Using Headers
-@emph{walk through an example of adding a UDP header}
-
-@section Using Tags
-@emph{walk through an example of adding a flow ID}
-
-@section Using Fragmentation
-@emph{walk through an example of link-layer fragmentation/reassembly}
-
-@section Sample program
-The below sample program (from @code{ns3/samples/main-packet.cc}) illustrates
-some use of the Packet, Header, and Tag classes.
-
+Here is a simple example illustrating the use of tags from the
+code in @code{src/internet-stack/udp-socket-impl.cc}:
 @verbatim
-/* -*-    Mode:C++; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
-#include "ns3/packet.h"
-#include "ns3/header.h"
-#include <iostream>
+  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);
+@end verbatim
 
-using namespace ns3;
-
-/* A sample Header implementation
- */
-class MyHeader : public Header {
-public:
-    MyHeader ();
-    virtual ~MyHeader ();
+This tag is read at the IP layer, then stripped (@code{src/internet-stack/ipv4-l3-protocol.cc}:
+@verbatim
+  uint8_t ttl = m_defaultTtl;
+  SocketIpTtlTag tag;
+  bool found = packet->RemovePacketTag (tag);
+  if (found)
+    {
+      ttl = tag.GetTtl ();
+    }
+@end verbatim
 
-    void SetData (uint16_t data);
-    uint16_t GetData (void) const;
-private:
-    virtual void PrintTo (std::ostream &os) const;
-    virtual void SerializeTo (Buffer::Iterator start) const;
-    virtual void DeserializeFrom (Buffer::Iterator start);
-    virtual uint32_t GetSerializedSize (void) const;
+@subsection Fragmentation and concatenation
 
-    uint16_t m_data;
-};
+Packets may be fragmented or merged together.  For example, to 
+fragment a packet @code{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:
+@verbatim
+  Ptr<Packet> frag0 = p->CreateFragment (0, 10);
+  Ptr<Packet> frag1 = p->CreateFragment (10, 90);
+@end verbatim
+
+As discussed above, the packet tags from @code{p} will follow to both
+packet fragments, and the byte tags will follow the byte ranges as needed.
 
-MyHeader::MyHeader ()
-{}
-MyHeader::~MyHeader ()
-{}
-void 
-MyHeader::PrintTo (std::ostream &os) const
-{
-    os << "MyHeader data=" << m_data << std::endl;
-}
-uint32_t
-MyHeader::GetSerializedSize (void) const
-{
-    return 2;
-}
-void 
-MyHeader::SerializeTo (Buffer::Iterator start) const
-{
-    // serialize in head of buffer
-    start.WriteHtonU16 (m_data);
-}
-void 
-MyHeader::DeserializeFrom (Buffer::Iterator start)
-{
-    // deserialize from head of buffer
-    m_data = start.ReadNtohU16 ();
-}
+Now, to put them back together:
+@verbatim
+  frag0->AddAtEnd (frag1);
+@end verbatim
+Now frag0 should be equivalent to the original packet @code{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.
+
+@subsection 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.
 
-void 
-MyHeader::SetData (uint16_t data)
-{
-    m_data = data;
-}
-uint16_t 
-MyHeader::GetData (void) const
-{
-    return m_data;
-}
-
-/* A sample Tag implementation
- */
-struct MyTag {
-    uint16_t m_streamId;
-};
-
-static TagRegistration<struct MyTag> g_MyTagRegistration ("ns3::MyTag", 0);
-
+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 @code{Packet::Print ()} method that uses
+the metadata to analyze the content of the packet's buffer.
 
-static void
-Receive (Packet p)
-{
-    MyHeader my;
-    p.Peek (my);
-    p.Remove (my);
-    std::cout << "received data=" << my.GetData () << std::endl;
-    struct MyTag myTag;
-    p.PeekTag (myTag);
-}
-
+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.
 
-int main (int argc, char *argv[])
-{
-    Packet p;
-    MyHeader my;
-    my.SetData (2);
-    std::cout << "send data=2" << std::endl;
-    p.Add (my);
-    struct MyTag myTag;
-    myTag.m_streamId = 5;
-    p.AddTag (myTag);
-    Receive (p);
-    return 0;
-}
+To enable this operation, users will typically insert one or both
+of these statements at the beginning of their programs:
+@verbatim
+  Packet::EnablePrinting ();
+  Packet::EnableChecking ();
 @end verbatim
 
+@section Sample programs
+
+See @code{samples/main-packet.cc} and @code{samples/main-packet-tag.cc}.
+
 @section Implementation details
 
 @subsection Private member variables
@@ -457,13 +534,19 @@
 A Packet object's interface provides access to some private
 data:
 @verbatim
-    Buffer m_buffer;
-    Tags m_tags;
-    uint32_t m_uid; 
-    static uint32_t m_global_uid;
+  Buffer m_buffer;
+  ByteTagList m_byteTagList;
+  PacketTagList m_packetTagList;
+  PacketMetadata m_metadata;
+  mutable uint32_t m_refCount;
+  static uint32_t m_globalUid;
 @end verbatim
-Each Packet has a Buffer and a Tags object, and a 32-bit unique ID (m\_uid).
-A static member variable keeps track of the UIDs allocated.  Note
+Each Packet has a Buffer and two Tags lists, a PacketMetadata object,
+and a ref count.
+A static member variable keeps track of the UIDs allocated.  
+The actual uid of the packet is stored in the PacketMetadata.
+
+Note
 that real network packets do not have a UID; the UID is therefore an
 instance of data that normally would be stored as a Tag in the packet.
 However, it was felt that a UID is a special case that is so often
@@ -525,6 +608,9 @@
 then complete their state-changing operation.
 
 @subsection Tags implementation
+
+(XXX revise me)
+
 Tags are implemented by a single pointer which points to the start of a 
 linked list ofTagData data structures. Each TagData structure points 
 to the next TagData in the list (its next pointer contains zero to 
@@ -562,12 +648,8 @@
 };
 @end verbatim
 
-@emph{add description of TagRegistration for printing}
-
 @subsection Memory management
 
-@emph{Describe free list.}
-
 @emph{Describe dataless vs. data-full packets.}
 
 @subsection Copy-on-write semantics
@@ -590,21 +672,26 @@
 
 Dirty operations:
 @itemize @bullet
-@item Packet::RemoveTag()
-@item Packet::Add()
-@item both versions of ns3::Packet::AddAtEnd()
+@item ns3::Packet::AddHeader
+@item ns3::Packet::AddTrailer
+@item both versions of ns3::Packet::AddAtEnd
+@item  ns3::Packet::RemovePacketTag
 @end itemize
 
 Non-dirty operations:
 @itemize @bullet
-@item Packet::AddTag()
-@item Packet::RemoveAllTags()
-@item Packet::PeekTag()
-@item Packet::Peek()
-@item Packet::Remove()
-@item Packet::CreateFragment()
-@item Packet::RemoveAtStart()
-@item Packet::RemoveAtEnd()
+@item ns3::Packet::AddPacketTag
+@item ns3::Packet::PeekPacketTag
+@item ns3::Packet::RemoveAllPacketTags
+@item ns3::Packet::AddByteTag
+@item ns3::Packet::FindFirstMatchingByteTag
+@item ns3::Packet::RemoveAllByteTags
+@item ns3::Packet::RemoveHeader
+@item ns3::Packet::RemoveTrailer
+@item ns3::Packet::CreateFragment
+@item ns3::Packet::RemoveAtStart
+@item ns3::Packet::RemoveAtEnd
+@item ns3::Packet::CopyData
 @end itemize
 
 Dirty operations will always be slower than non-dirty operations,