merge with HEAD
authorMathieu Lacage <mathieu.lacage@sophia.inria.fr>
Fri, 16 May 2008 15:52:04 -0700
changeset 3082 42a9a69ac4ef
parent 3081 de6acde26560 (current diff)
parent 3062 d7a198241e61 (diff)
child 3083 7172d5dcae51
merge with HEAD
examples/mixed-wireless.cc
src/common/tag-registry.cc
src/common/tag-registry.h
src/common/tag.h
src/common/tags.cc
src/common/tags.h
src/internet-node/ascii-trace.cc
src/internet-node/ascii-trace.h
src/internet-node/pcap-trace.cc
src/internet-node/pcap-trace.h
src/mobility/hierarchical-mobility-model.cc
src/mobility/mobility-model-notifier.cc
src/mobility/mobility-model-notifier.h
--- a/examples/csma-packet-socket.cc	Thu May 15 11:37:36 2008 -0700
+++ b/examples/csma-packet-socket.cc	Fri May 16 15:52:04 2008 -0700
@@ -38,9 +38,6 @@
 #include "ns3/node-module.h"
 #include "ns3/helper-module.h"
 
-#include "ns3/ascii-trace.h"
-#include "ns3/pcap-trace.h"
-
 using namespace ns3;
 
 NS_LOG_COMPONENT_DEFINE ("CsmaPacketSocketExample");
@@ -105,9 +102,9 @@
   // Configure tracing of all enqueue, dequeue, and NetDevice receive events
   // Trace output will be sent to the csma-packet-socket.tr file
   NS_LOG_INFO ("Configure Tracing.");
-  AsciiTrace asciitrace ("csma-packet-socket.tr");
-  asciitrace.TraceAllNetDeviceRx ();
-  asciitrace.TraceAllQueues ();
+  std::ofstream os;
+  os.open ("csma-packet-socket.tr");
+  csma.EnableAsciiAll (os);
 
   NS_LOG_INFO ("Run Simulation.");
   Simulator::Run ();
--- a/examples/mixed-global-routing.cc	Thu May 15 11:37:36 2008 -0700
+++ b/examples/mixed-global-routing.cc	Fri May 16 15:52:04 2008 -0700
@@ -40,8 +40,6 @@
 #include "ns3/simulator-module.h"
 #include "ns3/node-module.h"
 #include "ns3/helper-module.h"
-#include "ns3/ascii-trace.h"
-#include "ns3/pcap-trace.h"
 #include "ns3/global-route-manager.h"
 
 using namespace ns3;
--- a/examples/mixed-wireless.cc	Thu May 15 11:37:36 2008 -0700
+++ b/examples/mixed-wireless.cc	Fri May 16 15:52:04 2008 -0700
@@ -272,7 +272,6 @@
         {
           subnetAlloc->Add (Vector (0.0, j, 0.0));
         }
-      mobility.EnableNotifier ();
       mobility.PushReferenceMobilityModel (backbone.Get (i));
       mobility.SetPositionAllocator (subnetAlloc);
       mobility.SetMobilityModel ("ns3::RandomDirection2dMobilityModel",
@@ -347,7 +346,7 @@
   CsmaHelper::EnablePcap ("mixed-wireless", appSink->GetId (), 0);
 
 #ifdef ENABLE_FOR_TRACING_EXAMPLE
-  Config::Connect ("/NodeList/*/$MobilityModelNotifier/CourseChange",
+  Config::Connect ("/NodeList/*/$MobilityModel/CourseChange",
     MakeCallback (&CourseChangeCallback));
 #endif
 
--- a/samples/main-packet-tag.cc	Thu May 15 11:37:36 2008 -0700
+++ b/samples/main-packet-tag.cc	Fri May 16 15:52:04 2008 -0700
@@ -19,6 +19,7 @@
  */
 #include "ns3/tag.h"
 #include "ns3/packet.h"
+#include "ns3/uinteger.h"
 #include <iostream>
 
 using namespace ns3;
@@ -27,22 +28,11 @@
 class MyTag : public Tag
 {
 public:
-  // we have to define a public constructor
-  MyTag ();
-  // we have to define a public copy constructor
-  MyTag (const MyTag &other);
-  // we have to define a public destructor
-  ~MyTag ();
-  // we have to define a public static GetUid method
-  static uint32_t GetUid (void);
-  // we have to define a public Print method
-  void Print (std::ostream &os) const;
-  // we have to define a public GetSerializedSize method
-  uint32_t GetSerializedSize (void) const;
-  // we have to define a public Serialize method
-  void Serialize (Buffer::Iterator i) const;
-  // we have to define a public Deserialize method
-  uint32_t Deserialize (Buffer::Iterator i);
+  static TypeId GetTypeId (void);
+  virtual TypeId GetInstanceTypeId (void) const;
+  virtual uint32_t GetSerializedSize (void) const;
+  virtual void Serialize (TagBuffer i) const;
+  virtual void Deserialize (TagBuffer i);
   
   // these are our accessors to our tag structure
   void SetSimpleValue (uint8_t value);
@@ -51,52 +41,40 @@
   uint8_t m_simpleValue;
 };
 
-MyTag::MyTag ()
-{}
-MyTag::MyTag (const MyTag &other)
-  : m_simpleValue (other.m_simpleValue)
-{}
-MyTag::~MyTag ()
-{}
-uint32_t 
-MyTag::GetUid (void)
+TypeId 
+MyTag::GetTypeId (void)
 {
-  // we input a unique string to AllocateUid
-  // to avoid name collisions.
-  static uint32_t uid = AllocateUid<MyTag> ("MyTag.tests.nsnam.org");
-  return uid;
+  static TypeId tid = TypeId ("ns3::MyTag")
+    .SetParent<Tag> ()
+    .AddConstructor<MyTag> ()
+    .AddAttribute ("SimpleValue",
+                   "A simple value",
+                   EmptyAttributeValue (),
+                   MakeUintegerAccessor (&MyTag::GetSimpleValue),
+                   MakeUintegerChecker<uint8_t> ())
+    ;
+  return tid;
 }
-void 
-MyTag::Print (std::ostream &os) const
+TypeId 
+MyTag::GetInstanceTypeId (void) const
 {
-  // print the content of this tag for Packet::PrintTags
-  os << "MyTag=0x" << std::hex << (uint32_t)m_simpleValue << std::dec;
+  return GetTypeId ();
 }
 uint32_t 
 MyTag::GetSerializedSize (void) const
 {
-  // we do not want to deal with parallel simulations
-  // so we return 0.
-  return 0;
+  return 1;
 }
 void 
-MyTag::Serialize (Buffer::Iterator i) const
-{
-  // we will never be invoked because we are not doing
-  // parallel simulations so, we assert.
-  NS_ASSERT (false);
-}
-uint32_t
-MyTag::Deserialize (Buffer::Iterator i)
+MyTag::Serialize (TagBuffer i) const
 {
-  // we will never be invoked because we are not doing
-  // parallel simulations so, we assert.
-  NS_ASSERT (false);
-  // theoretically, return the number of bytes read
-  return 0;
+  i.WriteU8 (m_simpleValue);
 }
-
-
+void 
+MyTag::Deserialize (TagBuffer i)
+{
+  m_simpleValue = i.ReadU8 ();
+}
 void 
 MyTag::SetSimpleValue (uint8_t value)
 {
@@ -124,7 +102,7 @@
 
   // read the tag from the packet copy
   MyTag tagCopy;
-  p->PeekTag (tagCopy);
+  p->FindFirstMatchingTag (tagCopy);
 
   // the copy and the original are the same !
   NS_ASSERT (tagCopy.GetSimpleValue () == tag.GetSimpleValue ());
--- a/samples/main-random-topology.cc	Thu May 15 11:37:36 2008 -0700
+++ b/samples/main-random-topology.cc	Fri May 16 15:52:04 2008 -0700
@@ -25,7 +25,6 @@
   c.Create (10000);
 
   MobilityHelper mobility;
-  mobility.EnableNotifier ();
   mobility.SetPositionAllocator ("ns3::RandomDiscPositionAllocator",
                                  "X", StringValue ("100.0"),
                                  "Y", StringValue ("100.0"),
--- a/samples/main-random-walk.cc	Thu May 15 11:37:36 2008 -0700
+++ b/samples/main-random-walk.cc	Fri May 16 15:52:04 2008 -0700
@@ -8,7 +8,7 @@
 using namespace ns3;
 
 static void 
-CourseChange (ns3::TraceContext const&, Ptr<const MobilityModel> mobility)
+CourseChange (std::string foo, Ptr<const MobilityModel> mobility)
 {
   Vector pos = mobility->GetPosition ();
   Vector vel = mobility->GetVelocity ();
@@ -22,7 +22,7 @@
   Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Mode", StringValue ("Time"));
   Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Time", StringValue ("2s"));
   Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Speed", StringValue ("Constant:1.0"));
-  Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Bounds", StringValue ("0:200:0:100"));
+  Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Bounds", StringValue ("0|200|0|200"));
 
   CommandLine cmd;
   cmd.Parse (argc, argv);
@@ -31,7 +31,6 @@
   c.Create (100);
 
   MobilityHelper mobility;
-  mobility.EnableNotifier ();
   mobility.SetPositionAllocator ("ns3::RandomDiscPositionAllocator",
                                  "X", StringValue ("100.0"),
                                  "Y", StringValue ("100.0"),
@@ -40,9 +39,9 @@
                              "Mode", StringValue ("Time"),
                              "Time", StringValue ("2s"),
                              "Speed", StringValue ("Constant:1.0"),
-                             "Bounds", StringValue ("0:200:0:100"));
+                             "Bounds", StringValue ("0|200|0|200"));
   mobility.InstallAll ();
-  Config::Connect ("/NodeList/*/$ns3::MobilityModelNotifier/CourseChange",
+  Config::Connect ("/NodeList/*/$ns3::MobilityModel/CourseChange",
                    MakeCallback (&CourseChange));
 
   Simulator::StopAt (Seconds (100.0));
--- a/src/applications/udp-echo/udp-echo-client.cc	Thu May 15 11:37:36 2008 -0700
+++ b/src/applications/udp-echo/udp-echo-client.cc	Fri May 16 15:52:04 2008 -0700
@@ -93,7 +93,7 @@
 {
   NS_LOG_FUNCTION_NOARGS ();
 
-  if (!m_socket)
+  if (m_socket == 0)
     {
       TypeId tid = TypeId::LookupByName ("ns3::Udp");
       Ptr<SocketFactory> socketFactory = 
@@ -113,10 +113,10 @@
 {
   NS_LOG_FUNCTION_NOARGS ();
 
-  if (!m_socket) 
+  if (m_socket != 0) 
     {
-      m_socket->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>, Ptr<Packet>,
-                                const Address &> ());
+      m_socket->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>, 
+        Ptr<Packet>, const Address &> ());
     }
 
   Simulator::Cancel(m_sendEvent);
--- a/src/applications/udp-echo/udp-echo-server.cc	Thu May 15 11:37:36 2008 -0700
+++ b/src/applications/udp-echo/udp-echo-server.cc	Fri May 16 15:52:04 2008 -0700
@@ -69,13 +69,14 @@
 {
   NS_LOG_FUNCTION_NOARGS ();
 
-  if (!m_socket)
+  if (m_socket == 0)
     {
       TypeId tid = TypeId::LookupByName ("ns3::Udp");
       Ptr<SocketFactory> socketFactory = 
         GetNode ()->GetObject<SocketFactory> (tid);
       m_socket = socketFactory->CreateSocket ();
-      InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), m_port);
+      InetSocketAddress local = 
+        InetSocketAddress (Ipv4Address::GetAny (), m_port);
       m_socket->Bind (local);
     }
 
@@ -87,7 +88,7 @@
 {
   NS_LOG_FUNCTION_NOARGS ();
 
-  if (!m_socket) 
+  if (m_socket != 0) 
     {
       m_socket->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>, 
         Ptr<Packet>, const Address &> ());
--- a/src/common/buffer.cc	Thu May 15 11:37:36 2008 -0700
+++ b/src/common/buffer.cc	Fri May 16 15:52:04 2008 -0700
@@ -333,9 +333,10 @@
   return m_end - (m_zeroAreaEnd - m_zeroAreaStart);
 }
 
-void 
+bool
 Buffer::AddAtStart (uint32_t start)
 {
+  bool dirty;
   NS_ASSERT (CheckInternalState ());
   bool isDirty = m_data->m_count > 1 && m_start > m_data->m_dirtyStart;
   if (m_start >= start && !isDirty)
@@ -347,31 +348,11 @@
        */
       NS_ASSERT (m_data->m_count == 1 || m_start == m_data->m_dirtyStart);
       m_start -= start;
+      dirty = m_start > m_data->m_dirtyStart;
       HEURISTICS (g_nAddNoRealloc++);
     } 
-#if 0
-  // the following is an optimization
-  else if (m_start >= start)
-    {
-      struct BufferData *newData = Buffer::Create (m_data->m_size);
-      memcpy (newData->m_data + m_start, m_data->m_data + m_start, GetInternalSize ());
-      m_data->m_count--;
-      if (m_data->m_count == 0)
-        {
-          Buffer::Recycle (m_data);
-        }
-      m_data = newData;
-
-      m_start -= start;
-      HEURISTICS (g_nAddRealloc++);
-    }
   else
     {
-      NS_ASSERT (m_start < start);
-#else
-  else
-    {
-#endif
       uint32_t newSize = GetInternalSize () + start;
       struct BufferData *newData = Buffer::Create (newSize);
       memcpy (newData->m_data + start, m_data->m_data + m_start, GetInternalSize ());
@@ -383,10 +364,13 @@
       m_data = newData;
 
       int32_t delta = start - m_start;
-      m_start = 0;
+      m_start += delta;
       m_zeroAreaStart += delta;
       m_zeroAreaEnd += delta;
       m_end += delta;
+      m_start -= start;
+
+      dirty = true;
 
       HEURISTICS (g_nAddRealloc++);
     }
@@ -396,10 +380,12 @@
   m_data->m_dirtyEnd = m_end;
   LOG_INTERNAL_STATE ("add start=" << start << ", ");
   NS_ASSERT (CheckInternalState ());
+  return dirty;
 }
-void 
+bool
 Buffer::AddAtEnd (uint32_t end)
 {
+  bool dirty;
   NS_ASSERT (CheckInternalState ());
   bool isDirty = m_data->m_count > 1 && m_end < m_data->m_dirtyEnd;
   if (GetInternalEnd () + end <= m_data->m_size && !isDirty)
@@ -412,25 +398,10 @@
       NS_ASSERT (m_data->m_count == 1 || m_end == m_data->m_dirtyEnd);
       m_end += end;
 
+      dirty = m_end < m_data->m_dirtyEnd;
+
       HEURISTICS (g_nAddNoRealloc++);
     } 
-#if 0
-  // this is an optimization
-  else if (GetInternalEnd () + end > m_data->m_size)
-    {
-      struct BufferData *newData = Buffer::Create (newSize);
-      memcpy (newData->m_data + m_start, m_data->m_data + m_start, GetInternalSize ());
-      m_data->m_count--;
-      if (m_data->m_count == 0) 
-        {
-          Buffer::Recycle (m_data);
-        }
-      m_data = newData;
-
-      m_end += end;
-      HEURISTICS (g_nAddRealloc++);
-    }
-#endif
   else
     {
       uint32_t newSize = GetInternalSize () + end;
@@ -443,13 +414,14 @@
         }
       m_data = newData;
 
+      int32_t delta = -m_start;
+      m_zeroAreaStart += delta;
+      m_zeroAreaEnd += delta;
+      m_end += delta;
+      m_start += delta;
+      m_end += end;
 
-      m_zeroAreaStart -= m_start;
-      m_zeroAreaEnd -= m_start;
-      m_end -= m_start;
-      m_start = 0;
-
-      m_end += end;
+      dirty = true;
 
       HEURISTICS (g_nAddRealloc++);
     } 
@@ -459,12 +431,16 @@
   m_data->m_dirtyEnd = m_end;
   LOG_INTERNAL_STATE ("add end=" << end << ", ");
   NS_ASSERT (CheckInternalState ());
+
+  return dirty;
 }
 
-void 
+void
 Buffer::AddAtEnd (const Buffer &o)
 {
-  if (m_end == m_zeroAreaEnd &&
+  if (m_data->m_count == 1 &&
+      m_end == m_zeroAreaEnd &&
+      m_end == m_data->m_dirtyEnd &&
       o.m_start == o.m_zeroAreaStart &&
       o.m_zeroAreaEnd - o.m_zeroAreaStart > 0)
     {
@@ -476,6 +452,7 @@
       uint32_t zeroSize = o.m_zeroAreaEnd - o.m_zeroAreaStart;
       m_zeroAreaEnd += zeroSize;
       m_end = m_zeroAreaEnd;
+      m_data->m_dirtyEnd = m_zeroAreaEnd;
       uint32_t endData = o.m_end - o.m_zeroAreaEnd;
       AddAtEnd (endData);
       Buffer::Iterator dst = End ();
@@ -485,6 +462,7 @@
       dst.Write (src, o.End ());
       return;
     }
+
   Buffer dst = CreateFullCopy ();
   Buffer src = o.CreateFullCopy ();
 
@@ -608,6 +586,18 @@
   return *this;
 }
 
+int32_t 
+Buffer::GetCurrentStartOffset (void) const
+{
+  return m_start;
+}
+int32_t 
+Buffer::GetCurrentEndOffset (void) const
+{
+  return m_end;
+}
+
+
 void
 Buffer::TransformIntoRealBuffer (void) const
 {
--- a/src/common/buffer.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/common/buffer.h	Fri May 16 15:52:04 2008 -0700
@@ -392,6 +392,7 @@
 
   /**
    * \param start size to reserve
+   * \returns true if the buffer needed resizing, false otherwise.
    *
    * Add bytes at the start of the Buffer. The
    * content of these bytes is undefined but debugging
@@ -399,9 +400,10 @@
    * Any call to this method invalidates any Iterator
    * pointing to this Buffer.
    */
-  void AddAtStart (uint32_t start);
+  bool AddAtStart (uint32_t start);
   /**
    * \param end size to reserve
+   * \returns true if the buffer needed resizing, false otherwise.
    *
    * Add bytes at the end of the Buffer. The
    * content of these bytes is undefined but debugging
@@ -409,8 +411,15 @@
    * Any call to this method invalidates any Iterator
    * pointing to this Buffer.
    */
-  void AddAtEnd (uint32_t end);
+  bool AddAtEnd (uint32_t end);
 
+  /**
+   * \param o the buffer to append to the end of this buffer.
+   *
+   * Add bytes at the end of the Buffer.
+   * Any call to this method invalidates any Iterator
+   * pointing to this Buffer.
+   */
   void AddAtEnd (const Buffer &o);
   /**
    * \param start size to remove
@@ -451,6 +460,9 @@
 
   Buffer CreateFullCopy (void) const;
 
+  int32_t GetCurrentStartOffset (void) const;
+  int32_t GetCurrentEndOffset (void) const;
+
   Buffer (Buffer const &o);
   Buffer &operator = (Buffer const &o);
   Buffer ();
--- a/src/common/packet-metadata-test.cc	Thu May 15 11:37:36 2008 -0700
+++ b/src/common/packet-metadata-test.cc	Fri May 16 15:52:04 2008 -0700
@@ -28,7 +28,9 @@
 #include "packet.h"
 #include "packet-metadata.h"
 
-namespace ns3 {
+using namespace ns3;
+
+namespace {
 
 template <int N>
 class HistoryHeader : public Header
@@ -191,6 +193,10 @@
   return N;
 }
 
+}
+
+namespace ns3 {
+
 
 
 class PacketMetadataTest : public Test {
@@ -607,6 +613,17 @@
   p = Create<Packet> (16383);
   p = Create<Packet> (16384);
 
+
+  // bug 179.
+  p = Create<Packet> (40);
+  p2 = p->CreateFragment (5, 5);
+  p3 = p->CreateFragment (10, 30);
+  ADD_HEADER (p2, 8);
+  ADD_HEADER (p3, 8);
+  REM_HEADER (p2, 8);
+  REM_HEADER (p3, 8);
+  p2->AddAtEnd (p3);
+
   return ok;
 }
 
--- a/src/common/packet-metadata.cc	Thu May 15 11:37:36 2008 -0700
+++ b/src/common/packet-metadata.cc	Fri May 16 15:52:04 2008 -0700
@@ -178,6 +178,14 @@
   value >>= 8;
   buffer[1] = value;
 }
+void
+PacketMetadata::Append32 (uint32_t value,  uint8_t *buffer)
+{
+  buffer[0] = value & 0xff;
+  buffer[1] = (value >> 8) & 0xff;
+  buffer[2] = (value >> 16) & 0xff;
+  buffer[3] = (value >> 24) & 0xff;
+}
 bool
 PacketMetadata::TryToAppend16 (uint16_t value,  uint8_t **pBuffer, uint8_t *end)
 {
@@ -397,29 +405,24 @@
   NS_ASSERT (m_used != item->prev && m_used != item->next);
   uint32_t typeUidSize = GetUleb128Size (item->typeUid);
   uint32_t sizeSize = GetUleb128Size (item->size);
-  uint32_t n = typeUidSize + sizeSize + 2 + 2 + 2;
- restart:
-  if (m_used + n <= m_data->m_size &&
-      (m_head == 0xffff ||
-       m_data->m_count == 1 ||
-       m_used == m_data->m_dirtyEnd))
-    {
-      uint8_t *buffer = &m_data->m_data[m_used];
-      Append16 (item->next, buffer);
-      buffer += 2;
-      Append16 (item->prev, buffer);
-      buffer += 2;
-      AppendValue (item->typeUid, buffer);
-      buffer += typeUidSize;
-      AppendValue (item->size, buffer);
-      buffer += sizeSize;
-      Append16 (item->chunkUid, buffer);
-    }
-  else
+  uint32_t n =  2 + 2 + typeUidSize + sizeSize + 2;
+  if (m_used + n > m_data->m_size ||
+      (m_head != 0xffff &&
+       m_data->m_count != 1 &&
+       m_used != m_data->m_dirtyEnd))
     {
       ReserveCopy (n);
-      goto restart;
     }
+  uint8_t *buffer = &m_data->m_data[m_used];
+  Append16 (item->next, buffer);
+  buffer += 2;
+  Append16 (item->prev, buffer);
+  buffer += 2;
+  AppendValue (item->typeUid, buffer);
+  buffer += typeUidSize;
+  AppendValue (item->size, buffer);
+  buffer += sizeSize;
+  Append16 (item->chunkUid, buffer);
   return n;
 }
 
@@ -431,43 +434,40 @@
   NS_ASSERT (m_data != 0);
   uint32_t typeUid = ((item->typeUid & 0x1) == 0x1)?item->typeUid:item->typeUid+1;
   NS_ASSERT (m_used != prev && m_used != next);
- append:
-  uint8_t *start = &m_data->m_data[m_used];
-  uint8_t *end = &m_data->m_data[m_data->m_size];
-  if (end - start >= 14 &&
-      (m_head == 0xffff ||
-       m_data->m_count == 1 ||
-       m_used == m_data->m_dirtyEnd))
-    {
-      uint8_t *buffer = start;
+
+  uint32_t typeUidSize = GetUleb128Size (typeUid);
+  uint32_t sizeSize = GetUleb128Size (item->size);
+  uint32_t fragStartSize = GetUleb128Size (extraItem->fragmentStart);
+  uint32_t fragEndSize = GetUleb128Size (extraItem->fragmentEnd);
+  uint32_t n = 2 + 2 + typeUidSize + sizeSize + 2 + fragStartSize + fragEndSize + 4;
 
-      Append16 (next, buffer);
-      buffer += 2;
-      Append16 (prev, buffer);
-      buffer += 2;
-      if (TryToAppend (typeUid, &buffer, end) &&
-          TryToAppend (item->size, &buffer, end) &&
-          TryToAppend16 (item->chunkUid, &buffer, end) &&
-          TryToAppend (extraItem->fragmentStart, &buffer, end) &&
-          TryToAppend (extraItem->fragmentEnd, &buffer, end) &&
-          TryToAppend32 (extraItem->packetUid, &buffer, end))
-        {
-          uintptr_t written = buffer - start;
-          NS_ASSERT (written <= 0xffff);
-          NS_ASSERT (written >= 14);
-          return written;
-        }
+  if (m_used + n > m_data->m_size ||
+      (m_head != 0xffff &&
+       m_data->m_count != 1 &&
+       m_used != m_data->m_dirtyEnd))
+    {
+      ReserveCopy (n);
     }
 
-  uint32_t n = GetUleb128Size (typeUid);
-  n += GetUleb128Size (item->size);
-  n += 2;
-  n += GetUleb128Size (extraItem->fragmentStart);
-  n += GetUleb128Size (extraItem->fragmentEnd);
-  n += 4;
-  n += 2 + 2;
-  ReserveCopy (n);
-  goto append;
+  uint8_t *buffer = &m_data->m_data[m_used];
+
+  Append16 (next, buffer);
+  buffer += 2;
+  Append16 (prev, buffer);
+  buffer += 2;
+  AppendValue (typeUid, buffer);
+  buffer += typeUidSize;
+  AppendValue (item->size, buffer);
+  buffer += sizeSize;
+  Append16 (item->chunkUid, buffer);
+  buffer += 2;
+  AppendValue (extraItem->fragmentStart, buffer);
+  buffer += fragStartSize;
+  AppendValue (extraItem->fragmentEnd, buffer);
+  buffer += fragEndSize;
+  Append32 (extraItem->packetUid, buffer);
+
+  return n;
 }
 
 void
--- a/src/common/packet-metadata.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/common/packet-metadata.h	Fri May 16 15:52:04 2008 -0700
@@ -249,13 +249,14 @@
                     uint32_t available);
   inline void UpdateHead (uint16_t written);
   inline void UpdateTail (uint16_t written);
-  uint32_t GetUleb128Size (uint32_t value) const;
+  inline 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 void Append32 (uint32_t value, uint8_t *buffer);
   inline bool TryToAppend (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);
+  inline 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);
--- a/src/common/packet.cc	Thu May 15 11:37:36 2008 -0700
+++ b/src/common/packet.cc	Fri May 16 15:52:04 2008 -0700
@@ -24,6 +24,55 @@
 
 uint32_t Packet::m_globalUid = 0;
 
+TypeId 
+TagIterator::Item::GetTypeId (void) const
+{
+  return m_tid;
+}
+uint32_t 
+TagIterator::Item::GetStart (void) const
+{
+  return m_start;
+}
+uint32_t 
+TagIterator::Item::GetEnd (void) const
+{
+  return m_end;
+}
+void 
+TagIterator::Item::GetTag (Tag &tag) const
+{
+  if (tag.GetInstanceTypeId () != GetTypeId ())
+    {
+      NS_FATAL_ERROR ("The tag you provided is not of the right type.");
+    }
+  tag.Deserialize (m_buffer);
+}
+TagIterator::Item::Item (TypeId tid, uint32_t start, uint32_t end, TagBuffer buffer)
+  : m_tid (tid),
+    m_start (start),
+    m_end (end),
+    m_buffer (buffer)
+{}
+bool 
+TagIterator::HasNext (void) const
+{
+  return m_current.HasNext ();
+}
+TagIterator::Item 
+TagIterator::Next (void)
+{
+  TagList::Iterator::Item i = m_current.Next ();
+  return TagIterator::Item (i.tid, 
+                            i.start-m_current.GetOffsetStart (), 
+                            i.end-m_current.GetOffsetStart (), 
+                            i.buf);
+}
+TagIterator::TagIterator (TagList::Iterator i)
+  : m_current (i)
+{}
+
+
 void 
 Packet::Ref (void) const
 {
@@ -50,7 +99,7 @@
 
 Packet::Packet ()
   : m_buffer (),
-    m_tags (),
+    m_tagList (),
     m_metadata (m_globalUid, 0),
     m_refCount (1)
 {
@@ -59,7 +108,7 @@
 
 Packet::Packet (const Packet &o)
   : m_buffer (o.m_buffer),
-    m_tags (o.m_tags),
+    m_tagList (o.m_tagList),
     m_metadata (o.m_metadata),
     m_refCount (1)
 {}
@@ -72,14 +121,14 @@
       return *this;
     }
   m_buffer = o.m_buffer;
-  m_tags = o.m_tags;
+  m_tagList = o.m_tagList;
   m_metadata = o.m_metadata;
   return *this;
 }
 
 Packet::Packet (uint32_t size)
   : m_buffer (size),
-    m_tags (),
+    m_tagList (),
     m_metadata (m_globalUid, size),
     m_refCount (1)
 {
@@ -87,7 +136,7 @@
 }
 Packet::Packet (uint8_t const*buffer, uint32_t size)
   : m_buffer (),
-    m_tags (),
+    m_tagList (),
     m_metadata (m_globalUid, size),
     m_refCount (1)
 {
@@ -97,9 +146,9 @@
   i.Write (buffer, size);
 }
 
-Packet::Packet (Buffer buffer, Tags tags, PacketMetadata metadata)
+Packet::Packet (const Buffer &buffer,  const TagList &tagList, const PacketMetadata &metadata)
   : m_buffer (buffer),
-    m_tags (tags),
+    m_tagList (tagList),
     m_metadata (metadata),
     m_refCount (1)
 {}
@@ -113,7 +162,7 @@
   PacketMetadata metadata = m_metadata.CreateFragment (start, end);
   // again, call the constructor directly rather than
   // through Create because it is private.
-  return Ptr<Packet> (new Packet (buffer, m_tags, metadata), false);
+  return Ptr<Packet> (new Packet (buffer, m_tagList, metadata), false);
 }
 
 uint32_t 
@@ -126,7 +175,13 @@
 Packet::AddHeader (const Header &header)
 {
   uint32_t size = header.GetSerializedSize ();
-  m_buffer.AddAtStart (size);
+  uint32_t orgStart = m_buffer.GetCurrentStartOffset ();
+  bool resized = m_buffer.AddAtStart (size);
+  if (resized)
+    {
+      m_tagList.AddAtStart (m_buffer.GetCurrentStartOffset () - orgStart,
+                            m_buffer.GetCurrentStartOffset () + size);
+    }
   header.Serialize (m_buffer.Begin ());
   m_metadata.AddHeader (header, size);
 }
@@ -142,7 +197,13 @@
 Packet::AddTrailer (const Trailer &trailer)
 {
   uint32_t size = trailer.GetSerializedSize ();
-  m_buffer.AddAtEnd (size);
+  uint32_t orgEnd = m_buffer.GetCurrentEndOffset ();
+  bool resized = m_buffer.AddAtEnd (size);
+  if (resized)
+    {
+      m_tagList.AddAtEnd (m_buffer.GetCurrentEndOffset () - orgEnd,
+                          m_buffer.GetCurrentEndOffset () - size);
+    }
   Buffer::Iterator end = m_buffer.End ();
   trailer.Serialize (end);
   m_metadata.AddTrailer (trailer, size);
@@ -159,17 +220,28 @@
 void 
 Packet::AddAtEnd (Ptr<const Packet> packet)
 {
+  uint32_t aStart = m_buffer.GetCurrentStartOffset ();
+  uint32_t bEnd = packet->m_buffer.GetCurrentEndOffset ();
   m_buffer.AddAtEnd (packet->m_buffer);
-  /**
-   * XXX: we might need to merge the tag list of the
-   * other packet into the current packet.
-   */
+  uint32_t appendPrependOffset = m_buffer.GetCurrentEndOffset () - packet->m_buffer.GetSize ();
+  m_tagList.AddAtEnd (m_buffer.GetCurrentStartOffset () - aStart, 
+                      appendPrependOffset);
+  TagList copy = packet->m_tagList;
+  copy.AddAtStart (m_buffer.GetCurrentEndOffset () - bEnd,
+                   appendPrependOffset);
+  m_tagList.Add (copy);
   m_metadata.AddAtEnd (packet->m_metadata);
 }
 void
 Packet::AddPaddingAtEnd (uint32_t size)
 {
-  m_buffer.AddAtEnd (size);
+  uint32_t orgEnd = m_buffer.GetCurrentEndOffset ();
+  bool resized = m_buffer.AddAtEnd (size);
+  if (resized)
+    {
+      m_tagList.AddAtEnd (m_buffer.GetCurrentEndOffset () - orgEnd,
+                          m_buffer.GetCurrentEndOffset () - size);
+    }
   m_metadata.AddPaddingAtEnd (size);
 }
 void 
@@ -188,7 +260,7 @@
 void 
 Packet::RemoveAllTags (void)
 {
-  m_tags.RemoveAll ();
+  m_tagList.RemoveAll ();
 }
 
 uint8_t const *
@@ -206,7 +278,8 @@
 void 
 Packet::PrintTags (std::ostream &os) const
 {
-  m_tags.Print (os, " ");
+  // XXX:
+  //m_tagList.Print (os, " ");
 }
 
 void 
@@ -350,20 +423,20 @@
   m_metadata.Serialize (buffer.Begin (), reserve);
 
   // write tags
-  reserve = m_tags.GetSerializedSize ();
-  buffer.AddAtStart (reserve);
-  m_tags.Serialize (buffer.Begin (), reserve);
+  //XXX
+  //reserve = m_tags.GetSerializedSize ();
+  //buffer.AddAtStart (reserve);
+  //m_tags.Serialize (buffer.Begin (), reserve);
   
   // aggregate byte buffer, metadata, and tags
   Buffer tmp = m_buffer.CreateFullCopy ();
-  buffer.AddAtStart (tmp.GetSize ());
-  buffer.Begin ().Write (tmp.Begin (), tmp.End ());
+  tmp.AddAtEnd (buffer);
   
   // write byte buffer size.
-  buffer.AddAtStart (4);
-  buffer.Begin ().WriteU32 (m_buffer.GetSize ());
+  tmp.AddAtStart (4);
+  tmp.Begin ().WriteU32 (m_buffer.GetSize ());
 
-  return buffer;
+  return tmp;
 }
 void 
 Packet::Deserialize (Buffer buffer)
@@ -376,11 +449,13 @@
   // read buffer.
   buf.RemoveAtEnd (buf.GetSize () - packetSize);
   m_buffer = buf;
+  buffer.RemoveAtStart (4 + packetSize);
+
 
   // read tags
-  buffer.RemoveAtStart (4 + packetSize);
-  uint32_t tagsDeserialized = m_tags.Deserialize (buffer.Begin ());
-  buffer.RemoveAtStart (tagsDeserialized);
+  //XXX
+  //uint32_t tagsDeserialized = m_tags.Deserialize (buffer.Begin ());
+  //buffer.RemoveAtStart (tagsDeserialized);
 
   // read metadata
   uint32_t metadataDeserialized = 
@@ -388,6 +463,38 @@
   buffer.RemoveAtStart (metadataDeserialized);
 }
 
+void 
+Packet::AddTag (const Tag &tag) const
+{
+  TagList *list = const_cast<TagList *> (&m_tagList);
+  TagBuffer buffer = list->Add (tag.GetInstanceTypeId (), tag.GetSerializedSize (), 
+                                 m_buffer.GetCurrentStartOffset (),
+                                 m_buffer.GetCurrentEndOffset ());
+  tag.Serialize (buffer);
+}
+TagIterator 
+Packet::GetTagIterator (void) const
+{
+  return TagIterator (m_tagList.Begin (m_buffer.GetCurrentStartOffset (), m_buffer.GetCurrentEndOffset ()));
+}
+
+bool 
+Packet::FindFirstMatchingTag (Tag &tag) const
+{
+  TypeId tid = tag.GetInstanceTypeId ();
+  TagIterator i = GetTagIterator ();
+  while (i.HasNext ())
+    {
+      TagIterator::Item item = i.Next ();
+      if (tid == item.GetTypeId ())
+        {
+          item.GetTag (tag);
+          return true;
+        }
+    }
+  return false;
+}
+
 std::ostream& operator<< (std::ostream& os, const Packet &packet)
 {
   packet.Print (os);
@@ -403,24 +510,187 @@
 
 #include "ns3/test.h"
 #include <string>
+#include <stdarg.h>
+
+using namespace ns3;
+
+namespace {
+
+class ATestTagBase : public Tag
+{
+public:
+  ATestTagBase () : m_error (false) {}
+  bool m_error;
+};
+
+template <int N>
+class ATestTag : public ATestTagBase
+{
+public:
+  static TypeId GetTypeId (void) {
+    std::ostringstream oss;
+    oss << "anon::ATestTag<" << N << ">";
+    static TypeId tid = TypeId (oss.str ().c_str ())
+      .SetParent<Tag> ()
+      .AddConstructor<ATestTag<N> > ()
+      .HideFromDocumentation ()
+      ;
+    return tid;
+  }
+  virtual TypeId GetInstanceTypeId (void) const {
+    return GetTypeId ();
+  }
+  virtual uint32_t GetSerializedSize (void) const {
+    return N;
+  }
+  virtual void Serialize (TagBuffer buf) const {
+    for (uint32_t i = 0; i < N; ++i)
+      {
+        buf.WriteU8 (N);
+      }
+  }
+  virtual void Deserialize (TagBuffer buf) {
+    for (uint32_t i = 0; i < N; ++i)
+      {
+        uint8_t v = buf.ReadU8 ();
+        if (v != N)
+          {
+            m_error = true;
+          }
+      }
+  }
+  ATestTag ()
+    : ATestTagBase () {}
+};
+
+class ATestHeaderBase : public Header
+{
+public:
+  ATestHeaderBase () : Header (), m_error (false) {}
+  bool m_error;
+};
+
+template <int N>
+class ATestHeader : public ATestHeaderBase
+{
+public:
+  static TypeId GetTypeId (void) {
+    std::ostringstream oss;
+    oss << "anon::ATestHeader<" << N << ">";
+    static TypeId tid = TypeId (oss.str ().c_str ())
+      .SetParent<Header> ()
+      .AddConstructor<ATestHeader<N> > ()
+      .HideFromDocumentation ()
+      ;
+    return tid;
+  }
+  virtual TypeId GetInstanceTypeId (void) const {
+    return GetTypeId ();
+  }
+  virtual uint32_t GetSerializedSize (void) const {
+    return N;
+  }
+  virtual void Serialize (Buffer::Iterator iter) const {
+    for (uint32_t i = 0; i < N; ++i)
+      {
+        iter.WriteU8 (N);
+      }
+  }
+  virtual uint32_t Deserialize (Buffer::Iterator iter) {
+    for (uint32_t i = 0; i < N; ++i)
+      {
+        uint8_t v = iter.ReadU8 ();
+        if (v != N)
+          {
+            m_error = true;
+          }
+      }
+    return N;
+  }
+  virtual void Print (std::ostream &os) const {
+  }
+  ATestHeader ()
+    : ATestHeaderBase () {}
+
+};
+
+struct Expected
+{
+  Expected (uint32_t n_, uint32_t start_, uint32_t end_)
+    : n (n_), start (start_), end (end_) {}
+  
+  uint32_t n;
+  uint32_t start;
+  uint32_t end;
+};
+
+}
+
+#define E(a,b,c) a,b,c
+
+#define CHECK(p, n, ...)                                \
+  if (!DoCheck (p, __FILE__, __LINE__, n, __VA_ARGS__)) \
+    {                                                   \
+      result = false;                                   \
+    }
 
 namespace ns3 {
 
-class PacketTest: public Test {
+
+class PacketTest: public Test 
+{
 public:
+  PacketTest ();
   virtual bool RunTests (void);
-  PacketTest ();
+private:
+  bool DoCheck (Ptr<const Packet> p, const char *file, int line, uint32_t n, ...);
 };
 
 
 PacketTest::PacketTest ()
   : Test ("Packet") {}
 
+bool
+PacketTest::DoCheck (Ptr<const Packet> p, const char *file, int line, uint32_t n, ...)
+{
+  bool result = true;
+  std::vector<struct Expected> expected;
+  va_list ap;
+  va_start (ap, n);
+  for (uint32_t k = 0; k < n; ++k)
+    {
+      uint32_t N = va_arg (ap, uint32_t);
+      uint32_t start = va_arg (ap, uint32_t);
+      uint32_t end = va_arg (ap, uint32_t);
+      expected.push_back (Expected (N, start, end));
+    }
+  va_end (ap);
+
+  TagIterator i = p->GetTagIterator ();
+  uint32_t j = 0;
+  while (i.HasNext () && j < expected.size ())
+    {
+      TagIterator::Item item = i.Next ();
+      struct Expected e = expected[j];
+      std::ostringstream oss;
+      oss << "anon::ATestTag<" << e.n << ">";
+      NS_TEST_ASSERT_EQUAL_FILELINE (item.GetTypeId ().GetName (), oss.str (), file, line);
+      NS_TEST_ASSERT_EQUAL_FILELINE (item.GetStart (), e.start, file, line);
+      NS_TEST_ASSERT_EQUAL_FILELINE (item.GetEnd (), e.end, file, line);
+      ATestTagBase *tag = dynamic_cast<ATestTagBase *> (item.GetTypeId ().GetConstructor () ());
+      NS_TEST_ASSERT (tag != 0);
+      item.GetTag (*tag);
+      NS_TEST_ASSERT (!tag->m_error);
+      delete tag;
+      j++;
+    }
+  return result;
+}
 
 bool
 PacketTest::RunTests (void)
 {
-  bool ok = true;
+  bool result = true;
 
   Ptr<Packet> pkt1 = Create<Packet> (reinterpret_cast<const uint8_t*> ("hello"), 5);
   Ptr<Packet> pkt2 = Create<Packet> (reinterpret_cast<const uint8_t*> (" world"), 6);
@@ -428,25 +698,80 @@
   packet->AddAtEnd (pkt1);
   packet->AddAtEnd (pkt2);
   
-  if (packet->GetSize () != 11)
-    {
-      Failure () << "expected size 11, got " << packet->GetSize () << std::endl;
-      ok = false;
-    }
+  NS_TEST_ASSERT_EQUAL (packet->GetSize (), 11);
 
   std::string msg = std::string (reinterpret_cast<const char *>(packet->PeekData ()),
                                  packet->GetSize ());
-  if (msg != "hello world")
-    {
-      Failure () << "expected 'hello world', got '" << msg << "'" << std::endl;
-      ok = false;
-    }
+  NS_TEST_ASSERT_EQUAL (msg, "hello world");
+
+
+  Ptr<const Packet> p = Create<Packet> (1000);
+
+  p->AddTag (ATestTag<1> ());
+  CHECK (p, 1, E (1, 0, 1000));
+  Ptr<const Packet> copy = p->Copy ();
+  CHECK (copy, 1, E (1, 0, 1000));
+
+  p->AddTag (ATestTag<2> ());
+  CHECK (p, 2, E (1, 0, 1000), E(2, 0, 1000));
+  CHECK (copy, 1, E (1, 0, 1000));
+
+  {
+    Packet c0 = *copy;
+    Packet c1 = *copy;
+    c0 = c1;
+    CHECK (&c0, 1, E (1, 0, 1000));
+    CHECK (&c1, 1, E (1, 0, 1000));
+    CHECK (copy, 1, E (1, 0, 1000));
+    c0.AddTag (ATestTag<10> ());
+    CHECK (&c0, 2, E (1, 0, 1000), E (10, 0, 1000));
+    CHECK (&c1, 1, E (1, 0, 1000));
+    CHECK (copy, 1, E (1, 0, 1000));
+  }
 
-  return ok;
+  Ptr<Packet> frag0 = p->CreateFragment (0, 10);
+  Ptr<Packet> frag1 = p->CreateFragment (10, 90);
+  Ptr<const Packet> frag2 = p->CreateFragment (100, 900);
+  frag0->AddTag (ATestTag<3> ());
+  CHECK (frag0, 3, E (1, 0, 10), E(2, 0, 10), E (3, 0, 10));
+  frag1->AddTag (ATestTag<4> ());
+  CHECK (frag1, 3, E (1, 0, 90), E(2, 0, 90), E (4, 0, 90));
+  frag2->AddTag (ATestTag<5> ());
+  CHECK (frag2, 3, E (1, 0, 900), E(2, 0, 900), E (5, 0, 900));
+
+  frag1->AddAtEnd (frag2);
+  CHECK (frag1, 6, E (1, 0, 90), E(2, 0, 90), E (4, 0, 90), E (1, 90, 990), E(2, 90, 990), E (5, 90, 990));
+
+  CHECK (frag0, 3, E (1, 0, 10), E(2, 0, 10), E (3, 0, 10));
+  frag0->AddAtEnd (frag1);
+  CHECK (frag0, 9, 
+         E (1, 0, 10), E(2, 0, 10), E (3, 0, 10),
+         E (1, 10, 100), E(2, 10, 100), E (4, 10, 100), 
+         E (1, 100, 1000), E(2, 100, 1000), E (5, 100, 1000));
+
+
+  // force caching a buffer of the right size.
+  frag0 = Create<Packet> (1000);
+  frag0->AddHeader (ATestHeader<10> ());
+  frag0 = 0;
+
+  p = Create<Packet> (1000);
+  p->AddTag (ATestTag<20> ());
+  CHECK (p, 1, E (20, 0, 1000));
+  frag0 = p->CreateFragment (10, 90);
+  CHECK (p, 1, E (20, 0, 1000));
+  CHECK (frag0, 1, E (20, 0, 90));
+  p = 0;
+  frag0->AddHeader (ATestHeader<10> ());
+  CHECK (frag0, 1, E (20, 10, 100));
+
+  
+
+  return result;
 }
 
 
-static PacketTest gPacketTest;
+static PacketTest g_packetTest;
 
 }; // namespace ns3
 
--- a/src/common/packet.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/common/packet.h	Fri May 16 15:52:04 2008 -0700
@@ -24,9 +24,9 @@
 #include "buffer.h"
 #include "header.h"
 #include "trailer.h"
-#include "tags.h"
 #include "packet-metadata.h"
 #include "tag.h"
+#include "tag-list.h"
 #include "ns3/callback.h"
 #include "ns3/assert.h"
 #include "ns3/ptr.h"
@@ -34,9 +34,71 @@
 namespace ns3 {
 
 /**
+ * \brief Iterator over the set of tags in a packet
+ *
+ * This is a java-style iterator.
+ */
+class TagIterator
+{
+public:
+  /**
+   * Identifies a set tag and a set of bytes within a packet
+   * to which the tag applies.
+   */
+  class Item
+  {
+  public:
+    /**
+     * \returns the ns3::TypeId associated to this tag.
+     */
+    TypeId GetTypeId (void) const;
+    /**
+     * \returns the index of the first byte tagged by this tag.
+     *
+     * The index is an offset from the start of the packet.
+     */
+    uint32_t GetStart (void) const;
+    /**
+     * \returns the index of the last byte tagged by this tag.
+     *
+     * The index is an offset from the start of the packet.
+     */
+    uint32_t GetEnd (void) const;
+    /**
+     * \param tag the user tag to which the data should be copied.
+     *
+     * Read the requested tag and store it in the user-provided
+     * tag instance. This method will crash if the type of the
+     * tag provided by the user does not match the type of
+     * the underlying tag.
+     */
+    void GetTag (Tag &tag) const;
+  private:
+    friend class TagIterator;
+    Item (TypeId tid, uint32_t start, uint32_t end, TagBuffer buffer);
+    TypeId m_tid;
+    uint32_t m_start;
+    uint32_t m_end;
+    TagBuffer m_buffer;
+  };
+  /**
+   * \returns true if calling Next is safe, false otherwise.
+   */
+  bool HasNext (void) const;
+  /**
+   * \returns the next item found and prepare for the next one.
+   */
+  Item Next (void);
+private:
+  friend class Packet;
+  TagIterator (TagList::Iterator i);
+  TagList::Iterator m_current;
+};
+
+/**
  * \brief network packets
  *
- * Each network packet contains a byte buffer, a list of tags, and
+ * Each network packet contains a byte buffer, a set of tags, and
  * metadata.
  *
  * - The byte buffer stores the serialized content of the headers and trailers 
@@ -45,13 +107,10 @@
  * forces you to do this) which means that the content of a packet buffer
  * is expected to be that of a real packet.
  *
- * - The list of tags stores an arbitrarily large set of arbitrary 
- * user-provided data structures in the packet: 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. Each tag stored in the tag list can be at most
- * 16 bytes big. Trying to attach bigger data structures will trigger
- * crashes at runtime.
+ * - Each tag tags a subset of the bytes in the packet byte buffer with the 
+ * information stored in the tag. A classic example of a tag is a FlowIdTag 
+ * which contains a flow id: the set of bytes tagged by this tag implicitely 
+ * belong to the attached flow id.
  *
  * - The metadata describes the type of the headers and trailers which
  * were serialized in the byte buffer. The maintenance of metadata is
@@ -83,6 +142,8 @@
    * by getUid).
    */
   Packet ();
+  Packet (const Packet &o);
+  Packet &operator = (const Packet &o);  
   /**
    * Create a packet with a zero-filled payload.
    * The memory necessary for the payload is not allocated:
@@ -152,63 +213,6 @@
    */
   uint32_t RemoveTrailer (Trailer &trailer);
   /**
-   * \param tag a pointer to the tag to attach to this packet.
-   *
-   * Attach a tag to this packet. The tag is fully copied
-   * in a packet-specific internal buffer. This operation 
-   * is expected to be really fast. The copy constructor of the
-   * tag is invoked to copy it into the tag buffer.
-   *
-   * 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).
-   *
-   */
-  template <typename T>
-  void AddTag (T const &tag) const;
-  /**
-   * Remove a tag from this packet. The data stored internally
-   * for this tag is copied in the input tag if an instance
-   * of this tag type is present in the internal buffer. If this
-   * tag type is not present, the input tag is not modified. 
-   *
-   * This operation can be potentially slow and might trigger
-   * unexpectedly large memory allocations. It is thus
-   * usually a better idea to create a copy of this packet,
-   * and invoke removeAllTags on the copy to remove all 
-   * tags rather than remove the tags one by one from a packet.
-   *
-   * \param tag a pointer to the tag to remove from this packet
-   * \returns true if an instance of this tag type is stored
-   *          in this packet, false otherwise.
-   */
-  template <typename T>
-  bool RemoveTag (T &tag);
-  /**
-   * Copy a tag stored internally to the input tag. If no instance
-   * of this tag is present internally, the input tag is not modified.
-   * The copy constructor of the tag is invoked to copy it into the 
-   * input tag variable.
-   *
-   * \param tag a pointer to the tag to read from this packet
-   * \returns true if an instance of this tag type is stored
-   *          in this packet, false otherwise.
-   */
-  template <typename T>
-  bool PeekTag (T &tag) const;
-  /**
-   * Remove all the tags stored in this packet. This operation is
-   * much much faster than invoking removeTag n times.
-   */
-  void RemoveAllTags (void);
-  /**
    * \param os output stream in which the data should be printed.
    *
    * Iterate over the tags present in this packet, and
@@ -330,12 +334,47 @@
    * a different CPU.
    */
   void Deserialize (Buffer buffer);
+
+  /**
+   * \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 AddTag (const Tag &tag) const;
+  /**
+   * \returns an iterator over the set of tags included in this packet.
+   */
+  TagIterator GetTagIterator (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 FindFirstMatchingTag (Tag &tag) const;
+
+  /**
+   * Remove all the tags stored in this packet.
+   */
+  void RemoveAllTags (void);
+
 private:
-  Packet (Buffer buffer, Tags tags, PacketMetadata metadata);
-  Packet (const Packet &o);
-  Packet &operator = (const Packet &o);
+  Packet (const Buffer &buffer, const TagList &tagList, const PacketMetadata &metadata);
   Buffer m_buffer;
-  Tags m_tags;
+  TagList m_tagList;
   PacketMetadata m_metadata;
   mutable uint32_t m_refCount;
   static uint32_t m_globalUid;
@@ -381,42 +420,4 @@
 
 } // namespace ns3
 
-
-/**************************************************
-  Start of implementation of templates defined
-  above
- *************************************************/
-
-namespace ns3 {
-
-template <typename T>
-void Packet::AddTag (T const& tag) const
-{
-  const Tag *parent;
-  // if the following assignment fails, it is because the
-  // input to this function is not a subclass of the Tag class.
-  parent = &tag;
-  m_tags.Add (tag);
-}
-template <typename T>
-bool Packet::RemoveTag (T & tag)
-{
-  Tag *parent;
-  // if the following assignment fails, it is because the
-  // input to this function is not a subclass of the Tag class.
-  parent = &tag;
-  return m_tags.Remove (tag);
-}
-template <typename T>
-bool Packet::PeekTag (T & tag) const
-{
-  Tag *parent;
-  // if the following assignment fails, it is because the
-  // input to this function is not a subclass of the Tag class.
-  parent = &tag;
-  return m_tags.Peek (tag);
-}
-
-} // namespace ns3
-
 #endif /* PACKET_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag-buffer.cc	Fri May 16 15:52:04 2008 -0700
@@ -0,0 +1,193 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * 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 "tag-buffer.h"
+#include "ns3/assert.h"
+#include <string.h>
+
+namespace ns3 {
+
+#ifndef TAG_BUFFER_USE_INLINE
+
+void 
+TagBuffer::WriteU8 (uint8_t v)
+{
+  NS_ASSERT (m_current + 1 <= m_end);
+  *m_current = v;
+  m_current++;
+}
+
+void 
+TagBuffer::WriteU16 (uint16_t data)
+{
+  WriteU8 ((data >> 0) & 0xff);
+  WriteU8 ((data >> 8) & 0xff);
+}
+void 
+TagBuffer::WriteU32 (uint32_t data)
+{
+  WriteU8 ((data >> 0) & 0xff);
+  WriteU8 ((data >> 8) & 0xff);
+  WriteU8 ((data >> 16) & 0xff);
+  WriteU8 ((data >> 24) & 0xff);
+}
+
+
+uint8_t  
+TagBuffer::ReadU8 (void)
+{
+  NS_ASSERT (m_current + 1 <= m_end);
+  uint8_t v;
+  v = *m_current;
+  m_current++;
+  return v;
+}
+
+uint16_t 
+TagBuffer::ReadU16 (void)
+{
+  uint8_t byte0 = ReadU8 ();
+  uint8_t byte1 = ReadU8 ();
+  uint16_t data = byte1;
+  data <<= 8;
+  data |= byte0;
+  return data;
+}
+uint32_t 
+TagBuffer::ReadU32 (void)
+{
+  uint8_t byte0 = ReadU8 ();
+  uint8_t byte1 = ReadU8 ();
+  uint8_t byte2 = ReadU8 ();
+  uint8_t byte3 = ReadU8 ();
+  uint32_t data = byte3;
+  data <<= 8;
+  data |= byte2;
+  data <<= 8;
+  data |= byte1;
+  data <<= 8;
+  data |= byte0;
+  return data;
+}
+
+#endif /* TAG_BUFFER_USE_INLINE */
+
+
+void 
+TagBuffer::WriteU64 (uint64_t data)
+{
+  WriteU8 ((data >> 0) & 0xff);
+  WriteU8 ((data >> 8) & 0xff);
+  WriteU8 ((data >> 16) & 0xff);
+  WriteU8 ((data >> 24) & 0xff);
+  WriteU8 ((data >> 32) & 0xff);
+  WriteU8 ((data >> 40) & 0xff);
+  WriteU8 ((data >> 48) & 0xff);
+  WriteU8 ((data >> 54) & 0xff);
+}
+void
+TagBuffer::WriteDouble (double v)
+{
+  uint8_t *buf = (uint8_t *)&v;
+  for (uint32_t i = 0; i < sizeof (double); ++i, ++buf)
+    {
+      WriteU8 (*buf);
+    }
+}
+void 
+TagBuffer::Write (const uint8_t *buffer, uint32_t size)
+{
+  for (uint32_t i = 0; i < size; ++i, ++buffer)
+    {
+      WriteU8 (*buffer);
+    }
+}
+uint64_t 
+TagBuffer::ReadU64 (void)
+{
+  uint8_t byte0 = ReadU8 ();
+  uint8_t byte1 = ReadU8 ();
+  uint8_t byte2 = ReadU8 ();
+  uint8_t byte3 = ReadU8 ();
+  uint8_t byte4 = ReadU8 ();
+  uint8_t byte5 = ReadU8 ();
+  uint8_t byte6 = ReadU8 ();
+  uint8_t byte7 = ReadU8 ();
+  uint32_t data = byte7;
+  data <<= 8;
+  data |= byte6;
+  data <<= 8;
+  data |= byte5;
+  data <<= 8;
+  data |= byte4;
+  data <<= 8;
+  data |= byte3;
+  data <<= 8;
+  data |= byte2;
+  data <<= 8;
+  data |= byte1;
+  data <<= 8;
+  data |= byte0;
+
+  return data;
+}
+double
+TagBuffer::ReadDouble (void)
+{
+  double v;
+  uint8_t *buf = (uint8_t *)&v;
+  for (uint32_t i = 0; i < sizeof (double); ++i, ++buf)
+    {
+      *buf = ReadU8 ();
+    }
+  return v;
+}
+void 
+TagBuffer::Read (uint8_t *buffer, uint32_t size)
+{
+  for (uint32_t i = 0; i < size; ++i, ++buffer)
+    {
+      *buffer = ReadU8 ();
+    }
+}
+TagBuffer::TagBuffer (uint8_t *start, uint8_t *end)
+  : m_current (start),
+    m_end (end)
+{}
+
+void 
+TagBuffer::TrimAtEnd (uint32_t trim)
+{
+  NS_ASSERT (m_current <= (m_end - trim));
+  m_end -= trim;
+}
+
+void 
+TagBuffer::CopyFrom (TagBuffer o)
+{
+  NS_ASSERT (o.m_end >= o.m_current);
+  NS_ASSERT (m_end >= m_current);
+  uintptr_t size = o.m_end - o.m_current;
+  NS_ASSERT (size <= (uintptr_t)(m_end - m_current));
+  memcpy (m_current, o.m_current, size);
+  m_current += size;
+}
+
+} // namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag-buffer.h	Fri May 16 15:52:04 2008 -0700
@@ -0,0 +1,139 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * 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 TAG_BUFFER_H
+#define TAG_BUFFER_H
+
+#include <stdint.h>
+
+#define TAG_BUFFER_USE_INLINE 1
+
+#ifdef TAG_BUFFER_USE_INLINE
+#define TAG_BUFFER_INLINE inline
+#else
+#define TAG_BUFFER_INLINE
+#endif
+
+namespace ns3 {
+
+/**
+ * \brief read and write tag data
+ *
+ * This class allows subclasses of the ns3::Tag base class
+ * to serialize and deserialize their data.
+ */
+class TagBuffer
+{
+public:
+  TagBuffer (uint8_t *start, uint8_t *end);
+  void TrimAtEnd (uint32_t trim);
+
+  TAG_BUFFER_INLINE void WriteU8 (uint8_t v);
+  TAG_BUFFER_INLINE void WriteU16 (uint16_t v);
+  TAG_BUFFER_INLINE void WriteU32 (uint32_t v);
+  void WriteU64 (uint64_t v);
+  void WriteDouble (double v);
+  void Write (const uint8_t *buffer, uint32_t size);
+  TAG_BUFFER_INLINE uint8_t  ReadU8 (void);
+  TAG_BUFFER_INLINE uint16_t ReadU16 (void);
+  TAG_BUFFER_INLINE uint32_t ReadU32 (void);
+  uint64_t ReadU64 (void);
+  double ReadDouble (void);
+  void Read (uint8_t *buffer, uint32_t size);
+
+  void CopyFrom (TagBuffer o);
+private:
+  
+  uint8_t *m_current;
+  uint8_t *m_end;
+};
+
+} // namespace ns3
+
+#ifdef TAG_BUFFER_USE_INLINE
+
+#include "ns3/assert.h"
+
+namespace ns3 {
+
+void 
+TagBuffer::WriteU8 (uint8_t v)
+{
+  NS_ASSERT (m_current + 1 <= m_end);
+  *m_current = v;
+  m_current++;
+}
+
+void 
+TagBuffer::WriteU16 (uint16_t data)
+{
+  WriteU8 ((data >> 0) & 0xff);
+  WriteU8 ((data >> 8) & 0xff);
+}
+void 
+TagBuffer::WriteU32 (uint32_t data)
+{
+  WriteU8 ((data >> 0) & 0xff);
+  WriteU8 ((data >> 8) & 0xff);
+  WriteU8 ((data >> 16) & 0xff);
+  WriteU8 ((data >> 24) & 0xff);
+}
+
+uint8_t  
+TagBuffer::ReadU8 (void)
+{
+  NS_ASSERT (m_current + 1 <= m_end);
+  uint8_t v;
+  v = *m_current;
+  m_current++;
+  return v;
+}
+
+uint16_t 
+TagBuffer::ReadU16 (void)
+{
+  uint8_t byte0 = ReadU8 ();
+  uint8_t byte1 = ReadU8 ();
+  uint16_t data = byte1;
+  data <<= 8;
+  data |= byte0;
+  return data;
+}
+uint32_t 
+TagBuffer::ReadU32 (void)
+{
+  uint8_t byte0 = ReadU8 ();
+  uint8_t byte1 = ReadU8 ();
+  uint8_t byte2 = ReadU8 ();
+  uint8_t byte3 = ReadU8 ();
+  uint32_t data = byte3;
+  data <<= 8;
+  data |= byte2;
+  data <<= 8;
+  data |= byte1;
+  data <<= 8;
+  data |= byte0;
+  return data;
+}
+
+} // namespace ns3
+
+#endif /* TAG_BUFFER_USE_INLINE */
+
+#endif /* TAG_BUFFER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag-list.cc	Fri May 16 15:52:04 2008 -0700
@@ -0,0 +1,402 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * 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 "tag-list.h"
+#include <vector>
+
+#define USE_FREE_LIST 1
+#define FREE_LIST_SIZE 1000
+
+namespace ns3 {
+
+struct TagListData {
+  uint32_t size;
+  uint32_t count;
+  uint32_t dirty;
+  uint8_t data[4];
+};
+
+#ifdef USE_FREE_LIST
+static class TagListDataFreeList : public std::vector<struct TagListData *>
+{
+public:
+  ~TagListDataFreeList ();
+} g_freeList;
+static uint32_t g_maxSize = 0;
+
+TagListDataFreeList::~TagListDataFreeList ()
+{
+  for (TagListDataFreeList::iterator i = begin ();
+       i != end (); i++)
+    {
+      uint8_t *buffer = (uint8_t *)(*i);
+      delete [] buffer;
+    }
+}
+#endif /* USE_FREE_LIST */
+
+TagList::Iterator::Item::Item (TagBuffer buf_)
+    : buf (buf_)
+{}
+
+bool 
+TagList::Iterator::HasNext (void) const
+{
+  return m_current < m_end;
+}
+struct TagList::Iterator::Item 
+TagList::Iterator::Next (void)
+{
+  NS_ASSERT (HasNext ());
+  struct Item item = Item (TagBuffer (m_current+16, m_end));
+  item.tid.SetUid (m_nextTid);
+  item.size = m_nextSize;
+  item.start = m_nextStart;
+  item.end = m_nextEnd;
+  item.start = std::max (item.start, m_offsetStart);
+  item.end = std::min (item.end, m_offsetEnd);
+  m_current += 4 + 4 + 4 + 4 + item.size;
+  item.buf.TrimAtEnd (m_end - m_current);
+  PrepareForNext ();
+  return item;
+}
+void
+TagList::Iterator::PrepareForNext (void)
+{
+  while (m_current < m_end)
+    {
+      TagBuffer buf = TagBuffer (m_current, m_end);
+      m_nextTid = buf.ReadU32 ();
+      m_nextSize = buf.ReadU32 ();
+      m_nextStart = buf.ReadU32 ();
+      m_nextEnd = buf.ReadU32 ();
+      if (m_nextStart > m_offsetEnd || m_nextEnd < m_offsetStart)
+	{
+	  m_current += 4 + 4 + 4 + 4 + m_nextSize;
+	}
+      else
+	{
+	  break;
+	}
+    }
+}
+TagList::Iterator::Iterator (uint8_t *start, uint8_t *end, uint32_t offsetStart, uint32_t offsetEnd)
+  : m_current (start),
+    m_end (end),
+    m_offsetStart (offsetStart),
+    m_offsetEnd (offsetEnd)
+{
+  PrepareForNext ();
+}
+
+uint32_t 
+TagList::Iterator::GetOffsetStart (void) const
+{
+  return m_offsetStart;
+}
+
+
+TagList::TagList ()
+  : m_used (0),
+    m_data (0)
+{}
+TagList::TagList (const TagList &o)
+  : m_used (o.m_used),
+    m_data (o.m_data)
+{
+  if (m_data != 0)
+    {
+      m_data->count++;
+    }
+}
+TagList &
+TagList::operator = (const TagList &o)
+{
+  if (this == &o)
+    {
+      return *this;
+    }
+
+  Deallocate (m_data);
+  m_data = o.m_data;
+  m_used = o.m_used;
+  if (m_data != 0)
+    {
+      m_data->count++;
+    }
+  return *this;
+}
+TagList::~TagList ()
+{
+  Deallocate (m_data);
+  m_data = 0;
+  m_used = 0;
+}
+
+TagBuffer
+TagList::Add (TypeId tid, uint32_t bufferSize, uint32_t start, uint32_t end)
+{
+  uint32_t spaceNeeded = m_used + bufferSize + 4 + 4 + 4 + 4;
+  NS_ASSERT (m_used <= spaceNeeded);
+  if (m_data == 0)
+    {
+      m_data = Allocate (spaceNeeded);
+      m_used = 0;
+    } 
+  else if (m_data->size < spaceNeeded ||
+	   (m_data->count != 1 && m_data->dirty != m_used))
+    {
+      struct TagListData *newData = Allocate (spaceNeeded);
+      memcpy (&newData->data, &m_data->data, m_used);
+      Deallocate (m_data);
+      m_data = newData;
+    }
+  TagBuffer tag = TagBuffer (&m_data->data[m_used], 
+			     &m_data->data[spaceNeeded]);
+  tag.WriteU32 (tid.GetUid ());
+  tag.WriteU32 (bufferSize);
+  tag.WriteU32 (start);
+  tag.WriteU32 (end);
+  m_used = spaceNeeded;
+  m_data->dirty = m_used;
+  return tag;
+}
+
+void 
+TagList::Add (const TagList &o)
+{
+  TagList::Iterator i = o.Begin (0, 0xffffffff);
+  while (i.HasNext ())
+    {
+      TagList::Iterator::Item item = i.Next ();
+      TagBuffer buf = Add (item.tid, item.size, item.start, item.end);
+      buf.CopyFrom (item.buf);
+    }
+}
+
+void 
+TagList::Remove (const Iterator &i)
+{
+  if (m_data == 0)
+    {
+      return;
+    } 
+  // XXX
+}
+
+void 
+TagList::RemoveAll (void)
+{
+  Deallocate (m_data);
+  m_data = 0;
+  m_used = 0;
+}
+
+TagList::Iterator 
+TagList::Begin (uint32_t offsetStart, uint32_t offsetEnd) const
+{
+  if (m_data == 0)
+    {
+      return Iterator (0, 0, offsetStart, offsetEnd);
+    }
+  else
+    {
+      return Iterator (m_data->data, &m_data->data[m_used], offsetStart, offsetEnd);
+    }
+}
+
+bool 
+TagList::IsDirtyAtEnd (uint32_t appendOffset)
+{
+  TagList::Iterator i = Begin (0, 0xffffffff);
+  while (i.HasNext ())
+    {
+      TagList::Iterator::Item item = i.Next ();
+      if (item.end > appendOffset)
+	{
+	  return true;
+	}
+    }
+  return false;
+}
+
+bool 
+TagList::IsDirtyAtStart (uint32_t prependOffset)
+{
+  TagList::Iterator i = Begin (0, 0xffffffff);
+  while (i.HasNext ())
+    {
+      TagList::Iterator::Item item = i.Next ();
+      if (item.start < prependOffset)
+	{
+	  return true;
+	}
+    }
+  return false;
+}
+
+void 
+TagList::AddAtEnd (int32_t adjustment, uint32_t appendOffset)
+{
+  if (adjustment == 0 && !IsDirtyAtEnd (appendOffset))
+    {
+      return;
+    }
+  TagList list;
+  TagList::Iterator i = Begin (0, 0xffffffff);
+  while (i.HasNext ())
+    {
+      TagList::Iterator::Item item = i.Next ();
+      item.start += adjustment;
+      item.end += adjustment;
+
+      if (item.start > appendOffset)
+	{
+	  continue;
+	}
+      else if (item.start < appendOffset && item.end > appendOffset)
+	{
+	  item.end = appendOffset;
+	}
+      else
+	{
+	  // nothing to do.
+	}
+      TagBuffer buf = list.Add (item.tid, item.size, item.start, item.end);
+      buf.CopyFrom (item.buf);
+    }
+  *this = list;  
+}
+
+void 
+TagList::AddAtStart (int32_t adjustment, uint32_t prependOffset)
+{
+  if (adjustment == 0 && !IsDirtyAtStart (prependOffset))
+    {
+      return;
+    }
+  TagList list;
+  TagList::Iterator i = Begin (0, 0xffffffff);
+  while (i.HasNext ())
+    {
+      TagList::Iterator::Item item = i.Next ();
+      item.start += adjustment;
+      item.end += adjustment;
+
+      if (item.end < prependOffset)
+	{
+	  continue;
+	}
+      else if (item.end > prependOffset && item.start < prependOffset)
+	{
+	  item.start = prependOffset;
+	}
+      else
+	{
+	  // nothing to do.
+	}
+      TagBuffer buf = list.Add (item.tid, item.size, item.start, item.end);
+      buf.CopyFrom (item.buf);
+    }
+  *this = list;    
+}
+
+#ifdef USE_FREE_LIST
+
+struct TagListData *
+TagList::Allocate (uint32_t size)
+{
+  while (!g_freeList.empty ())
+    {
+      struct TagListData *data = g_freeList.back ();
+      g_freeList.pop_back ();
+      NS_ASSERT (data != 0);
+      if (data->size >= size)
+	{
+	  data->count = 1;
+	  data->dirty = 0;
+	  return data;
+	}
+      uint8_t *buffer = (uint8_t *)data;
+      delete [] buffer;
+    }
+  uint8_t *buffer = new uint8_t [std::max (size, g_maxSize) + sizeof (struct TagListData) - 4];
+  struct TagListData *data = (struct TagListData *)buffer;
+  data->count = 1;
+  data->size = size;
+  data->dirty = 0;
+  return data;
+}
+
+void 
+TagList::Deallocate (struct TagListData *data)
+{
+  if (data == 0)
+    {
+      return;
+    }
+  g_maxSize = std::max (g_maxSize, data->size);
+  data->count--;
+  if (data->count == 0)
+    {
+      if (g_freeList.size () > FREE_LIST_SIZE ||
+	  data->size < g_maxSize)
+	{
+	  uint8_t *buffer = (uint8_t *)data;
+	  delete [] buffer;
+	}
+      else
+	{
+	  g_freeList.push_back (data);
+	}
+    }
+}
+
+#else /* USE_FREE_LIST */
+
+struct TagListData *
+TagList::Allocate (uint32_t size)
+{
+  uint8_t *buffer = new uint8_t [size + sizeof (struct TagListData) - 4];
+  struct TagListData *data = (struct TagListData *)buffer;
+  data->count = 1;
+  data->size = size;
+  data->dirty = 0;
+  return data;
+}
+
+void 
+TagList::Deallocate (struct TagListData *data)
+{
+  if (data == 0)
+    {
+      return;
+    }
+  data->count--;
+  if (data->count == 0)
+    {
+      uint8_t *buffer = (uint8_t *)data;
+      delete [] buffer;
+    }
+}
+
+#endif /* USE_FREE_LIST */
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag-list.h	Fri May 16 15:52:04 2008 -0700
@@ -0,0 +1,172 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * 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 TAG_LIST_H
+#define TAG_LIST_H
+
+#include <stdint.h>
+#include "ns3/type-id.h"
+#include "tag-buffer.h"
+
+namespace ns3 {
+
+struct TagListData;
+
+/**
+ * \brief keep track of the tags stored in a packet.
+ *
+ * This class is mostly private to the Packet implementation and users
+ * should never have to access it directly.
+ *
+ * \internal
+ * The implementation of this class is a bit tricky so, there are a couple
+ * of things to keep in mind here:
+ *
+ *   - it stores all tags in a single byte buffer: each tag is stored
+ *     as 4 32bit integers (TypeId, tag data size, start, end) followed 
+ *     by the tag data as generated by Tag::Serialize.
+ *
+ *   - the struct TagListData structure which contains the tag byte buffer
+ *     is shared and, thus, reference-counted. This data structure is unshared
+ *     as-needed to emulate COW semantics.
+ *
+ *   - each tag tags a unique set of bytes identified by the pair of offsets 
+ *     (start,end). These offsets are provided by Buffer::GetCurrentStartOffset
+ *     and Buffer::GetCurrentEndOffset which means that they are relative to 
+ *     the start of the 'virtual byte buffer' as explained in the documentation
+ *     for the ns3::Buffer class. Whenever the origin of the offset of the Buffer
+ *     instance associated to this TagList instance changes, the Buffer class
+ *     reports this to its container Packet class as a bool return value
+ *     in Buffer::AddAtStart and Buffer::AddAtEnd. In both cases, when this happens
+ *     the Packet class calls TagList::AddAtEnd and TagList::AddAtStart to update
+ *     the byte offsets of each tag in the TagList.
+ *
+ *   - whenever bytes are removed from the packet byte buffer, the TagList offsets 
+ *     are never updated because we rely on the fact that they will be updated in
+ *     either the next call to Packet::AddHeader or Packet::AddTrailer or when
+ *     the user iterates the tag list with Packet::GetTagIterator and 
+ *     TagIterator::Next.
+ */
+class TagList
+{
+public:
+
+  class Iterator
+  {
+  public:
+    struct Item 
+    {
+      TypeId tid;
+      uint32_t size;
+      uint32_t start;
+      uint32_t end;
+      TagBuffer buf;
+    private:
+      friend class TagList;
+      Item (TagBuffer buf);
+    };
+    bool HasNext (void) const;
+    struct TagList::Iterator::Item Next (void);
+    uint32_t GetOffsetStart (void) const;
+  private:
+    friend class TagList;
+    Iterator (uint8_t *start, uint8_t *end, uint32_t offsetStart, uint32_t offsetEnd);
+    void PrepareForNext (void);
+    uint8_t *m_current;
+    uint8_t *m_end;
+    uint32_t m_offsetStart;
+    uint32_t m_offsetEnd;
+    uint32_t m_nextTid;
+    uint32_t m_nextSize;
+    uint32_t m_nextStart;
+    uint32_t m_nextEnd;
+  };
+
+  TagList ();
+  TagList (const TagList &o);
+  TagList &operator = (const TagList &o);
+  ~TagList ();
+
+  /**
+   * \param tid the typeid of the tag added
+   * \param bufferSize the size of the tag when its serialization will 
+   *        be completed. Typically, the return value of Tag::GetSerializedSize
+   * \param start offset which uniquely identifies the first byte tagged by this tag.
+   * \param start offset which uniquely identifies the last byte tagged by this tag.
+   * \returns a buffer which can be used to write the tag data.     
+   *
+   * 
+   */
+  TagBuffer Add (TypeId tid, uint32_t bufferSize, uint32_t start, uint32_t end);
+
+  /**
+   * \param o the other list of tags to aggregate.
+   *
+   * Aggregate the two lists of tags.
+   */
+  void Add (const TagList &o);
+
+  /**
+   * \param i points to the item to remove from this list.
+   *
+   * Not implemented.
+   */
+  void Remove (const Iterator &i);
+  void RemoveAll (void);
+
+  /**
+   * \param offsetStart the offset which uniquely identifies the first data byte 
+   *        present in the byte buffer associated to this TagList.
+   * \param offsetEnd the offset which uniquely identifies the last data byte 
+   *        present in the byte buffer associated to this TagList.
+   * \returns an iterator
+   *
+   * The returned iterator will allow you to loop through the set of tags present
+   * in this list: the boundaries of each tag as reported by their start and
+   * end offsets will be included within the input offsetStart and offsetEnd.
+   */
+  TagList::Iterator Begin (uint32_t offsetStart, uint32_t offsetEnd) const;
+
+  /**
+   * Adjust the offsets stored internally by the adjustment delta and
+   * make sure that all offsets are smaller than appendOffset which represents
+   * the location where new bytes have been added to the byte buffer.
+   */
+  void AddAtEnd (int32_t adjustment, uint32_t appendOffset);
+  /**
+   * Adjust the offsets stored internally by the adjustment delta and
+   * make sure that all offsets are bigger than prependOffset which represents
+   * the location where new bytes have been added to the byte buffer.
+   */
+  void AddAtStart (int32_t adjustment, uint32_t prependOffset);
+
+private:
+  bool IsDirtyAtEnd (uint32_t appendOffset);
+  bool IsDirtyAtStart (uint32_t prependOffset);
+
+  struct TagListData *Allocate (uint32_t size);
+  void Deallocate (struct TagListData *data);
+
+  uint16_t m_used;
+  struct TagListData *m_data;
+};
+
+} // namespace ns3
+
+#endif /* TAG_LIST_H */
--- a/src/common/tag-registry.cc	Thu May 15 11:37:36 2008 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- *
- * 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 "tag-registry.h"
-#include "ns3/fatal-error.h"
-
-namespace ns3 {
-
-TagRegistry::TagInfoVector *
-TagRegistry::GetInfo (void)
-{
-  static TagRegistry::TagInfoVector vector;
-  return &vector;
-}
-
-std::string
-TagRegistry::GetUidString (uint32_t uid)
-{
-  TagInfo info = (*GetInfo ())[uid - 1];
-  return info.uidString;
-}
-uint32_t 
-TagRegistry::GetUidFromUidString (std::string uidString)
-{
-  TagInfoVector *vec = GetInfo ();
-  uint32_t uid = 1;
-  for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++)
-    {
-      if (i->uidString == uidString)
-        {
-          return uid;
-        }
-      uid++;
-    }
-  NS_FATAL_ERROR ("We are trying to deserialize an un-registered type. This can't work.");
-  return 0;
-}
-
-void 
-TagRegistry::Destruct (uint32_t uid, uint8_t *data)
-{
-  TagInfo info = (*GetInfo ())[uid - 1];
-  info.destruct (data);
-}
-void 
-TagRegistry::Print (uint32_t uid, uint8_t *data, std::ostream &os)
-{
-  TagInfo info = (*GetInfo ())[uid - 1];
-  info.print (data, os);
-}
-uint32_t
-TagRegistry::GetSerializedSize (uint32_t uid, uint8_t *data)
-{
-  TagInfo info = (*GetInfo ())[uid - 1];
-  return info.getSerializedSize (data);
-}
-void 
-TagRegistry::Serialize (uint32_t uid, uint8_t *data, Buffer::Iterator start)
-{
-  TagInfo info = (*GetInfo ())[uid - 1];
-  info.serialize (data, start);
-}
-uint32_t 
-TagRegistry::Deserialize (uint32_t uid, uint8_t *data, Buffer::Iterator start)
-{
-  TagInfo info = (*GetInfo ())[uid - 1];
-  return info.deserialize (data, start);
-}
-
-} // namespace ns3
--- a/src/common/tag-registry.h	Thu May 15 11:37:36 2008 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,148 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- *
- * 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 TAG_REGISTRY_H
-#define TAG_REGISTRY_H
-
-#include <string>
-#include <stdint.h>
-#include "buffer.h"
-
-namespace ns3 {
-
-/**
- * \brief a registry of all existing tag types.
- * \internal
- *
- * This class is used to give polymorphic access to the methods
- * exported by a tag. It also is used to associate a single
- * reliable uid to each unique type. 
- */
-class TagRegistry
-{
-public:
-  template <typename T>
-  static uint32_t Register (std::string uidString);
-  static std::string GetUidString (uint32_t uid);
-  static uint32_t GetUidFromUidString (std::string uidString);
-  static void Destruct (uint32_t uid, uint8_t *data);
-  static void Print (uint32_t uid, uint8_t *data, std::ostream &os);
-  static uint32_t GetSerializedSize (uint32_t uid, uint8_t *data);
-  static void Serialize (uint32_t uid, uint8_t *data, Buffer::Iterator start);
-  static uint32_t Deserialize (uint32_t uid, uint8_t *data, Buffer::Iterator start);
-private:
-  typedef void (*DestructCb) (uint8_t *);
-  typedef void (*PrintCb) (uint8_t *, std::ostream &);
-  typedef uint32_t (*GetSerializedSizeCb) (uint8_t *);
-  typedef void (*SerializeCb) (uint8_t *, Buffer::Iterator);
-  typedef uint32_t (*DeserializeCb) (uint8_t *, Buffer::Iterator);
-  struct TagInfo
-  {
-    std::string uidString;
-    DestructCb destruct;
-    PrintCb print;
-    GetSerializedSizeCb getSerializedSize;
-    SerializeCb serialize;
-    DeserializeCb deserialize;
-  };
-  typedef std::vector<struct TagInfo> TagInfoVector;
-
-  template <typename T>
-  static void DoDestruct (uint8_t *data);
-  template <typename T>
-  static void DoPrint (uint8_t *data, std::ostream &os);
-  template <typename T>
-  static uint32_t DoGetSerializedSize (uint8_t *data);
-  template <typename T>
-  static void DoSerialize (uint8_t *data, Buffer::Iterator start);
-  template <typename T>
-  static uint32_t DoDeserialize (uint8_t *data, Buffer::Iterator start);
-
-  static TagInfoVector *GetInfo (void);
-};
-
-} // namespace ns3
-
-namespace ns3 {
-
-template <typename T>
-void 
-TagRegistry::DoDestruct (uint8_t *data)
-{
-  T *tag = reinterpret_cast<T *> (data);
-  tag->~T ();  
-}
-template <typename T>
-void 
-TagRegistry::DoPrint (uint8_t *data, std::ostream &os)
-{
-  T *tag = reinterpret_cast<T *> (data);
-  tag->Print (os);
-}
-template <typename T>
-uint32_t 
-TagRegistry::DoGetSerializedSize (uint8_t *data)
-{
-  T *tag = reinterpret_cast<T *> (data);
-  return tag->GetSerializedSize ();
-}
-template <typename T>
-void 
-TagRegistry::DoSerialize (uint8_t *data, Buffer::Iterator start)
-{
-  T *tag = reinterpret_cast<T *> (data);
-  tag->Serialize (start);
-}
-template <typename T>
-uint32_t 
-TagRegistry::DoDeserialize (uint8_t *data, Buffer::Iterator start)
-{
-  T *tag = reinterpret_cast<T *> (data);
-  return tag->Deserialize (start);
-}
-
-template <typename T>
-uint32_t 
-TagRegistry::Register (std::string uidString)
-{
-  TagInfoVector *vec = GetInfo ();
-  uint32_t j = 0;
-  for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++)
-    {
-      if (i->uidString == uidString)
-        {
-          return j;
-        }
-      j++;
-    }
-  TagInfo info;
-  info.uidString = uidString;
-  info.destruct = &TagRegistry::DoDestruct<T>;
-  info.print = &TagRegistry::DoPrint<T>;
-  info.getSerializedSize = &TagRegistry::DoGetSerializedSize<T>;
-  info.serialize = &TagRegistry::DoSerialize<T>;
-  info.deserialize = &TagRegistry::DoDeserialize<T>;
-  vec->push_back (info);
-  uint32_t uid = vec->size ();
-  return uid;
-}
-
-} // namespace ns3
-
-#endif /* TAG_REGISTRY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag.cc	Fri May 16 15:52:04 2008 -0700
@@ -0,0 +1,34 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * 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 "tag.h"
+
+namespace ns3 {
+
+TypeId 
+Tag::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::Tag")
+    .SetParent<ObjectBase> ()
+    ;
+  return tid;
+}
+
+
+} // namespace ns3
--- a/src/common/tag.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/common/tag.h	Fri May 16 15:52:04 2008 -0700
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2006 INRIA
+ * Copyright (c) 2008 INRIA
  *
  * 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
@@ -20,106 +20,43 @@
 #ifndef TAG_H
 #define TAG_H
 
+#include "ns3/object-base.h"
+#include "tag-buffer.h"
 #include <stdint.h>
-#include <string>
-
-/**
- * \relates ns3::Tag
- * \brief this macro should be instantiated exactly once for each
- *        new type of Tag
- *
- * This macro will ensure that your new Tag type is registered
- * within the tag registry. In most cases, this macro
- * is not really needed but, for safety, please, use it all the
- * time.
- *
- * Note: This macro is _absolutely_ needed if you try to run a
- * distributed simulation.
- */
-#define NS_TAG_ENSURE_REGISTERED(x)	       \
-static class thisisaveryverylongclassname ##x  \
-{					       \
- public:				       \
-  thisisaveryverylongclassname ##x ()          \
-    { uint32_t uid; uid = x::GetUid ();}       \
-} g_thisisanotherveryveryverylongname ## x;
 
 namespace ns3 {
 
 /**
- * \brief a tag can be stored in a packet.
- *
- * A tag is a blob of 16 bytes of data which can be stored in
- * a packet: a packet can contain an arbitrary number of tags
- * and these tags are considered as "on-the-side" per-packet
- * data structures which are not taken into account when calculating
- * the size of the payload of a packet. They exist solely as 
- * simulation-specific objects.
- *
- * Tags are typically used to:
- *   - implement per-packet cross-layer communication
- *   - implement packet coloring: you could store a "color" tag
- *     in a packet to mark various types of packet for
- *     simulation analysis
+ * \brief tag a set of bytes in a packet
  *
- * To create a new type of tag, you must create a subclass
- * of the Tag base class which defines:
- *  - a public default constructor: needed for implementation
- *    purposes of the Packet code.
- *  - a public copy constructor: needed to copy a tag into
- *    a packet tag buffer when the user invokes Packet::AddTag
- *  - a public destructor: needed to destroy the copy of a tag
- *    stored in a packet buffer when the user invokes Packet::RemoveTag
- *    or when the packet is destroyed and the last reference to 
- *    a tag instance disapears.
- *  - a public static method named GetUid: needed to uniquely
- *    the type of each tag instance.
- *  - a public method named Print: needed to print the content
- *    of a tag when the user calls Packet::PrintTags
- *  - a public method named GetSerializedSize: needed to serialize
- *    the content of a tag to a byte buffer when a packet must
- *    be sent from one computing node to another in a parallel 
- *    simulation. If this method returns 0, it means that the
- *    tag does not need to be transfered from computing node to 
- *     computing node
- *  - a public method named Serialize: perform the serialization
- *    to a byte buffer upon transfer to a new computing node in a 
- *    parallel simulation.
- *  - a public method named Deserialize: invert the serialization
- *    from a byte buffer after being transfered to a new computing
- *    node in a parallel simulation.
- *
- * A detailed example of what these methods should look like
- * and how they should be implemented is described in samples/main-packet-tag.cc
+ * New kinds of tags can be created by subclassing this base class.
  */
-class Tag
+class Tag : public ObjectBase
 {
-protected:
+public:
+  static TypeId GetTypeId (void);
+
   /**
-   * \param name the unique name of the new type of tag
-   * \returns a newly-allocated uid
+   * \returns the number of bytes required to serialize the data of the tag.
+   *
+   * This method is typically invoked by Packet::AddTag just prior to calling
+   * Tag::Serialize.
+   */
+  virtual uint32_t GetSerializedSize (void) const = 0;
+  /**
+   * \param i the buffer to write data into.
    *
-   * This method should be used by subclasses to implement
-   * their static public GetUid method.
+   * Write the content of the tag in the provided tag buffer.
    */
-  template <typename T>
-  static uint32_t AllocateUid (std::string name);
+  virtual void Serialize (TagBuffer i) const = 0;
+  /**
+   * \param i the buffer to read data from.
+   *
+   * Read the content of the tag from the provided tag buffer.
+   */
+  virtual void Deserialize (TagBuffer i) = 0;
 };
 
 } // namespace ns3
 
-// implementation below.
-#include "tag-registry.h"
-
-namespace ns3 {
-
-template <typename T>
-uint32_t
-Tag::AllocateUid (std::string name)
-{
-  return TagRegistry::Register<T> (name);
-}
-
-} // namespace ns3
-
 #endif /* TAG_H */
--- a/src/common/tags.cc	Thu May 15 11:37:36 2008 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,529 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- *
- * 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 "tags.h"
-#include <string.h>
-#include "ns3/fatal-error.h"
-
-namespace ns3 {
-
-#ifdef USE_FREE_LIST
-
-struct Tags::TagData *Tags::gFree = 0;
-uint32_t Tags::gN_free = 0;
-
-struct Tags::TagData *
-Tags::AllocData (void) const
-{
-  struct Tags::TagData *retval;
-  if (gFree != 0) 
-    {
-      retval = gFree;
-      gFree = gFree->m_next;
-      gN_free--;
-    } 
-  else 
-    {
-      retval = new struct Tags::TagData ();
-    }
-  return retval;
-}
-
-void
-Tags::FreeData (struct TagData *data) const
-{
-  if (gN_free > 1000) 
-    {
-      delete data;
-      return;
-    }
-  gN_free++;
-  data->m_next = gFree;
-  data->m_id = 0;
-  gFree = data;
-}
-#else
-struct Tags::TagData *
-Tags::AllocData (void) const
-{
-  struct Tags::TagData *retval;
-  retval = new struct Tags::TagData ();
-  return retval;
-}
-
-void
-Tags::FreeData (struct TagData *data) const
-{
-  delete data;
-}
-#endif
-
-bool
-Tags::Remove (uint32_t id)
-{
-  bool found = false;
-  for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
-    {
-      if (cur->m_id == id) 
-        {
-          found = true;
-        }
-    }
-  if (!found) 
-    {
-      return false;
-    }
-  struct TagData *start = 0;
-  struct TagData **prevNext = &start;
-  for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
-    {
-      if (cur->m_id == id) 
-        {
-          /**
-           * XXX
-           * Note: I believe that we could optimize this to
-           * avoid copying each TagData located after the target id
-           * and just link the already-copied list to the next tag.
-           */
-          continue;
-        }
-      struct TagData *copy = AllocData ();
-      copy->m_id = cur->m_id;
-      copy->m_count = 1;
-      copy->m_next = 0;
-      memcpy (copy->m_data, cur->m_data, Tags::SIZE);
-      *prevNext = copy;
-      prevNext = &copy->m_next;
-    }
-  *prevNext = 0;
-  RemoveAll ();
-  m_next = start;
-  return true;
-}
-
-void 
-Tags::Print (std::ostream &os, std::string separator) const
-{
-  for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
-    {
-      TagRegistry::Print (cur->m_id, cur->m_data, os);
-      if (cur->m_next != 0)
-        {
-          os << separator;
-        }
-    }
-}
-
-uint32_t
-Tags::GetSerializedSize (void) const
-{
-  uint32_t totalSize = 4; // reserve space for the size of the tag data.
-  for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
-    {
-      uint32_t size = TagRegistry::GetSerializedSize (cur->m_id, cur->m_data);
-      if (size != 0)
-        {
-          std::string uidString = TagRegistry::GetUidString (cur->m_id);
-          totalSize += 4; // for the size of the string itself.
-          totalSize += uidString.size ();
-          totalSize += size;
-        }
-    }
-  return totalSize;
-}
-
-void 
-Tags::Serialize (Buffer::Iterator i, uint32_t totalSize) const
-{
-  i.WriteU32 (totalSize);
-  for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
-    {
-      uint32_t size = TagRegistry::GetSerializedSize (cur->m_id, cur->m_data);
-      if (size != 0)
-        {
-          std::string uidString = TagRegistry::GetUidString (cur->m_id);
-          i.WriteU32 (uidString.size ());
-          uint8_t *buf = (uint8_t *)uidString.c_str ();
-          i.Write (buf, uidString.size ());
-          TagRegistry::Serialize (cur->m_id, cur->m_data, i);
-        }
-    }
-}
-uint32_t
-Tags::Deserialize (Buffer::Iterator i)
-{
-  uint32_t totalSize = i.ReadU32 ();
-  uint32_t bytesRead = 4;
-  while (bytesRead < totalSize)
-    {
-      uint32_t uidStringSize = i.ReadU32 ();
-      bytesRead += 4;
-      std::string uidString;
-      uidString.reserve (uidStringSize);
-      for (uint32_t j = 0; j < uidStringSize; j++)
-        {
-          uint32_t c = i.ReadU8 ();
-          uidString.push_back (c);
-        }
-      bytesRead += uidStringSize;
-      uint32_t uid = TagRegistry::GetUidFromUidString (uidString);
-      struct TagData *newStart = AllocData ();
-      newStart->m_count = 1;
-      newStart->m_next = 0;
-      newStart->m_id = uid;
-      bytesRead += TagRegistry::Deserialize (uid, newStart->m_data, i);
-      newStart->m_next = m_next;
-      m_next = newStart;
-    }
-  NS_ASSERT (bytesRead == totalSize);
-  /**
-   * The process of serialization/deserialization 
-   * results in an inverted linked-list after
-   * deserialization so, we invert the linked-list
-   * in-place here.
-   * Note: the algorithm below is pretty classic
-   * but whenever I get to code it, it makes my
-   * brain hurt :)
-   */
-  struct TagData *prev = 0;
-  struct TagData *cur = m_next;
-  while (cur != 0)
-    {
-      struct TagData *next = cur->m_next;
-      cur->m_next = prev;
-      prev = cur;
-      cur = next;
-    }
-  m_next = prev;
-  return totalSize;
-}
-
-
-
-}; // namespace ns3
-
-#ifdef RUN_SELF_TESTS
-
-#include "ns3/test.h"
-#include <iomanip>
-#include <iostream>
-
-namespace ns3 {
-
-static bool g_a;
-static bool g_b;
-static bool g_c;
-static bool g_z;
-
-class TagsTest : Test {
-public:
-  TagsTest ();
-  virtual ~TagsTest ();
-  virtual bool RunTests (void);
-};
-
-class myTagA : public Tag
-{
-public:
-  static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagA> ("myTagA.test.nsnam.org"); return uid;}
-  void Print (std::ostream &os) const {g_a = true;}
-  uint32_t GetSerializedSize (void) const {return 1;}
-  void Serialize (Buffer::Iterator i) const {i.WriteU8 (a);}
-  uint32_t Deserialize (Buffer::Iterator i) {a = i.ReadU8 (); return 1;}
-
-  uint8_t a;
-};
-class myTagB : public Tag
-{
-public:
-  static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagB> ("myTagB.test.nsnam.org"); return uid;}
-  void Print (std::ostream &os) const {g_b = true;}
-  uint32_t GetSerializedSize (void) const {return 4;}
-  void Serialize (Buffer::Iterator i) const {i.WriteU32 (b);}
-  uint32_t Deserialize (Buffer::Iterator i) {b = i.ReadU32 (); return 4;}
-
-  uint32_t b;
-};
-class myTagC : public Tag
-{
-public:
-  static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagC> ("myTagC.test.nsnam.org"); return uid;}
-  void Print (std::ostream &os) const {g_c = true;}
-  uint32_t GetSerializedSize (void) const {return Tags::SIZE;}
-  void Serialize (Buffer::Iterator i) const {i.Write (c, Tags::SIZE);}
-  uint32_t Deserialize (Buffer::Iterator i) {i.Read (c, Tags::SIZE); return Tags::SIZE;}
-  uint8_t c [Tags::SIZE];
-};
-class myInvalidTag : public Tag
-{
-public:
-  static uint32_t GetUid (void) 
-  {static uint32_t uid = AllocateUid<myInvalidTag> ("myinvalidTag.test.nsnam.org"); return uid;}
-  void Print (std::ostream &os) const {}
-  uint32_t GetSerializedSize (void) const {return 0;}
-  void Serialize (Buffer::Iterator i) const {}
-  uint32_t Deserialize (Buffer::Iterator i) {return 0;}
-
-  uint8_t invalid [Tags::SIZE+1];
-};
-class myTagZ  : public Tag
-{
-public:
-  static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagZ> ("myTagZ.test.nsnam.org"); return uid;}
-  void Print (std::ostream &os) const {g_z = true;}
-  uint32_t GetSerializedSize (void) const {return 0;}
-  void Serialize (Buffer::Iterator i) const {}
-  uint32_t Deserialize (Buffer::Iterator i) {return 0;}
-
-  uint8_t z;
-};
-
-class MySmartTag : public Tag
-{
-public:
-  static uint32_t GetUid (void) 
-  {static uint32_t uid = AllocateUid<MySmartTag> ("MySmartTag.test.nsnam.org"); return uid;}
-  MySmartTag ()
-  {
-    //std::cout << "construct" << std::endl;
-  }
-  MySmartTag (const MySmartTag &o)
-  {
-    //std::cout << "copy" << std::endl;
-  }
-  ~MySmartTag ()
-  {
-    //std::cout << "destruct" << std::endl;
-  }
-  MySmartTag &operator = (const MySmartTag &o)
-  {
-    //std::cout << "assign" << std::endl;
-    return *this;
-  }
-  void Print (std::ostream &os) const {}
-  uint32_t GetSerializedSize (void) const {return 0;}
-  void Serialize (Buffer::Iterator i) const {}
-  uint32_t Deserialize (Buffer::Iterator i) {return 0;}
-};
-
-
-TagsTest::TagsTest ()
-  : Test ("Tags")
-{}
-TagsTest::~TagsTest ()
-{}
-
-bool 
-TagsTest::RunTests (void)
-{
-  bool ok = true;
-
-  // build initial tag.
-  Tags tags;
-  myTagA a;
-  a.a = 10;
-  tags.Add (a);
-  a.a = 0;
-  tags.Peek (a);
-  if (a.a != 10) 
-    {
-      ok = false;
-    }
-  g_a = false;
-  tags.Print (std::cout, "");
-  if (!g_a)
-    {
-      ok = false;
-    }
-  myTagB b;
-  b.b = 0xff;
-  tags.Add (b);
-  b.b = 0;
-  tags.Peek (b);
-  if (b.b != 0xff) 
-    {
-      ok = false;
-    }
-  g_b = false;
-  g_a = false;
-  tags.Print (std::cout, "");
-  if (!g_a || !g_b)
-    {
-      ok = false;
-    }
-  // make sure copy contains copy.
-  Tags other = tags;
-  g_b = false;
-  g_a = false;
-  other.Print (std::cout, "");
-  if (!g_a || !g_b)
-    {
-      ok = false;
-    }
-  g_b = false;
-  g_a = false;
-  tags.Print (std::cout, "");
-  if (!g_a || !g_b)
-    {
-      ok = false;
-    }
-  myTagA oA;
-  oA.a = 0;
-  other.Peek (oA);
-  if (oA.a != 10) 
-    {
-      ok = false;
-    }
-  myTagB oB;
-  oB.b = 1;
-  other.Peek (oB);
-  if (oB.b != 0xff) 
-    {
-      ok = false;
-    }
-  // remove data.
-  other.Remove (oA);
-  if (other.Peek (oA)) 
-    {
-      ok = false;
-    }
-  g_b = false;
-  g_a = false;
-  other.Print (std::cout, "");
-  if (g_a || !g_b)
-    {
-      ok = false;
-    }
-  if (!tags.Peek (oA)) 
-    {
-      ok = false;
-    }
-  other.Remove (oB);
-  if (other.Peek (oB)) 
-    {
-      ok = false;
-    }
-  if (!tags.Peek (oB)) 
-    {
-      ok = false;
-    }
-
-  other = tags;
-  Tags another = other;
-  myTagC c;
-  memset (c.c, 0x66, 16);
-  another.Add (c);
-  c.c[0] = 0;
-  another.Peek (c);
-  if (!another.Peek (c)) 
-    {
-      ok = false;
-    }
-  if (tags.Peek (c)) 
-    {
-      ok = false;
-    }
-
-  other = other;
-  //other.prettyPrint (std::cout);
-
-  //struct myInvalidTag invalid;
-  //tags.add (&invalid);
-
-  myTagZ tagZ;
-  Tags testLastTag;
-  tagZ.z = 0;
-  testLastTag.Add (tagZ);
-  g_z = false;
-  testLastTag.Print (std::cout, "");
-  if (!g_z)
-    {
-      ok = false;
-    }
-
-  MySmartTag smartTag;
-  {
-    Tags tmp;
-    tmp.Add (smartTag);
-    tmp.Peek (smartTag);
-    tmp.Remove (smartTag);
-  }
-
-  {
-    Tags source;
-    myTagA aSource;
-    aSource.a = 0x66;
-    source.Add (aSource);
-    Buffer buffer;
-    uint32_t serialized = source.GetSerializedSize ();
-    buffer.AddAtStart (serialized);
-    source.Serialize (buffer.Begin (), serialized);
-    Tags dest;
-    dest.Deserialize (buffer.Begin ());
-    myTagA aDest;
-    aDest.a = 0x55;
-    dest.Peek (aDest);
-    if (aDest.a != 0x66)
-      {
-        ok = false;
-      }
-  }
-
-  {
-    Tags source;
-    myTagA aSource;
-    aSource.a = 0x66;
-    source.Add (aSource);
-    myTagZ zSource;
-    zSource.z = 0x77;
-    source.Add (zSource);
-
-    Buffer buffer;
-    uint32_t serialized = source.GetSerializedSize ();
-    buffer.AddAtStart (serialized);
-    source.Serialize (buffer.Begin (), serialized);
-    Tags dest;
-    dest.Deserialize (buffer.Begin ());
-
-    myTagA aDest;
-    aDest.a = 0x55;
-    dest.Peek (aDest);
-    if (aDest.a != 0x66)
-      {
-        ok = false;
-      }
-    myTagZ zDest;
-    zDest.z = 0x44;
-    dest.Peek (zDest);
-    if (zDest.z != 0x44)
-      {
-        ok = false;
-      }
-  }
-
-  return ok;
-}
-
-static TagsTest gTagsTest;
-
-
-}; // namespace ns3
-
-#endif /* RUN_SELF_TESTS */
-
--- a/src/common/tags.h	Thu May 15 11:37:36 2008 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,228 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- *
- * 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 TAGS_H
-#define TAGS_H
-
-#include <stdint.h>
-#include <ostream>
-#include <vector>
-#include "buffer.h"
-
-namespace ns3 {
-
-/**
- * \ingroup constants
- * \brief Tag maximum size
- * The maximum size (in bytes) of a Tag is stored
- * in this constant.
- */
-#define TAGS_MAX_SIZE 16
-
-class Tags {
-public:
-  inline Tags ();
-  inline Tags (Tags const &o);
-  inline Tags &operator = (Tags const &o);
-  inline ~Tags ();
-
-  template <typename T>
-  void Add (T const&tag) const;
-
-  template <typename T>
-  bool Remove (T &tag);
-
-  template <typename T>
-  bool Peek (T &tag) const;
-
-  void Print (std::ostream &os, std::string separator) const;
-  uint32_t GetSerializedSize (void) const;
-  void Serialize (Buffer::Iterator i, uint32_t size) const;
-  uint32_t Deserialize (Buffer::Iterator i);
-
-  inline void RemoveAll (void);
-
-  enum {
-      SIZE = TAGS_MAX_SIZE
-  };
-private:
-  struct TagData {
-      uint8_t m_data[Tags::SIZE];
-      struct TagData *m_next;
-      uint32_t m_id;
-      uint32_t m_count;
-  };
-
-  bool Remove (uint32_t id);
-  struct Tags::TagData *AllocData (void) const;
-  void FreeData (struct TagData *data) const;
-
-  static struct Tags::TagData *gFree;
-  static uint32_t gN_free;
-
-  struct TagData *m_next;
-};
-
-} // namespace ns3
-
-
-
-/**************************************************************
-   An implementation of the templates defined above
- *************************************************************/
-#include "tag-registry.h"
-#include "tag.h"
-#include "ns3/assert.h"
-#include <string>
-
-namespace ns3 {
-
-template <typename T>
-void 
-Tags::Add (T const&tag) const
-{
-  const Tag *parent;
-  // if the following assignment fails, it is because the
-  // input to this function is not a subclass of the Tag class.
-  parent = &tag;
-
-  NS_ASSERT (sizeof (T) <= Tags::SIZE);
-  // ensure this id was not yet added
-  for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
-    {
-      NS_ASSERT (cur->m_id != T::GetUid ());
-    }
-  struct TagData *newStart = AllocData ();
-  newStart->m_count = 1;
-  newStart->m_next = 0;
-  newStart->m_id = T::GetUid ();
-  void *buf = &newStart->m_data;
-  new (buf) T (tag);
-  newStart->m_next = m_next;
-  const_cast<Tags *> (this)->m_next = newStart;
-}
-
-template <typename T>
-bool
-Tags::Remove (T &tag)
-{
-  Tag *parent;
-  // if the following assignment fails, it is because the
-  // input to this function is not a subclass of the Tag class.
-  parent = &tag;
-  NS_ASSERT (sizeof (T) <= Tags::SIZE);
-  if (Peek (tag))
-    {
-      Remove (T::GetUid ());
-      return true;
-    }
-  else
-    {
-      return false;
-    }
-}
-
-template <typename T>
-bool
-Tags::Peek (T &tag) const
-{
-  Tag *parent;
-  // if the following assignment fails, it is because the
-  // input to this function is not a subclass of the Tag class.
-  parent = &tag;
-  NS_ASSERT (sizeof (T) <= Tags::SIZE);
-  for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
-    {
-      if (cur->m_id == T::GetUid ()) 
-        {
-          /* found tag */
-          T *data = reinterpret_cast<T *> (&cur->m_data);
-          tag = T (*data);
-          return true;
-        }
-    }
-  /* no tag found */
-  return false;
-}
-
-Tags::Tags ()
-  : m_next ()
-{}
-
-Tags::Tags (Tags const &o)
-  : m_next (o.m_next)
-{
-  if (m_next != 0) 
-    {
-      m_next->m_count++;
-    }
-}
-
-Tags &
-Tags::operator = (Tags const &o)
-{
-  // self assignment
-  if (m_next == o.m_next) 
-    {
-      return *this;
-    }
-  RemoveAll ();
-  m_next = o.m_next;
-  if (m_next != 0) 
-    {
-      m_next->m_count++;
-    }
-  return *this;
-}
-
-Tags::~Tags ()
-{
-  RemoveAll ();
-}
-
-void
-Tags::RemoveAll (void)
-{
-  struct TagData *prev = 0;
-  for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
-    {
-      cur->m_count--;
-      if (cur->m_count > 0) 
-        {
-          break;
-        }
-      if (prev != 0) 
-        {
-          TagRegistry::Destruct (prev->m_id, prev->m_data);
-          FreeData (prev);
-        }
-      prev = cur;
-    }
-  if (prev != 0) 
-    {
-      TagRegistry::Destruct (prev->m_id, prev->m_data);
-      FreeData (prev);
-    }
-  m_next = 0;
-}
-
-
-}; // namespace ns3
-
-#endif /* TAGS_H */
--- a/src/common/wscript	Thu May 15 11:37:36 2008 -0700
+++ b/src/common/wscript	Fri May 16 15:52:04 2008 -0700
@@ -7,14 +7,15 @@
         'packet-metadata.cc',
         'packet-metadata-test.cc',
         'packet.cc',
-        'tags.cc',
-        'tag-registry.cc',
         'chunk.cc',
         'header.cc',
         'trailer.cc',
         'pcap-writer.cc',
         'data-rate.cc',
         'error-model.cc',
+        'tag.cc',
+        'tag-list.cc',
+        'tag-buffer.cc',
         ]
 
     headers = bld.create_obj('ns3header')
@@ -24,12 +25,12 @@
         'chunk.h',
         'header.h',
         'trailer.h',
-        'tags.h',
-        'tag-registry.h',
-        'tag.h',
         'packet.h',
         'packet-metadata.h',
         'pcap-writer.h',
         'data-rate.h',
         'error-model.h',
+        'tag.h',
+        'tag-list.h',
+        'tag-buffer.h',
         ]
--- a/src/contrib/delay-jitter-estimation.cc	Thu May 15 11:37:36 2008 -0700
+++ b/src/contrib/delay-jitter-estimation.cc	Fri May 16 15:52:04 2008 -0700
@@ -2,6 +2,7 @@
 #include "delay-jitter-estimation.h"
 #include "ns3/tag.h"
 #include "ns3/simulator.h"
+#include "ns3/string.h"
 
 namespace {
 
@@ -9,11 +10,13 @@
 {
 public:
   TimestampTag ();
-  static uint32_t GetUid (void);
-  void Print (std::ostream &os) const;
-  void Serialize (ns3::Buffer::Iterator start) const;
-  uint32_t Deserialize (ns3::Buffer::Iterator start);
-  uint32_t GetSerializedSize (void) const;
+  static ns3::TypeId GetTypeId (void);
+  virtual ns3::TypeId GetInstanceTypeId (void) const;
+
+  virtual uint32_t GetSerializedSize (void) const;
+  virtual void Serialize (ns3::TagBuffer i) const;
+  virtual void Deserialize (ns3::TagBuffer i);
+
 
   ns3::Time GetTxTime (void) const;
 private:
@@ -23,29 +26,41 @@
 TimestampTag::TimestampTag ()
   : m_creationTime (ns3::Simulator::Now ().GetTimeStep ())
 {}
-uint32_t 
-TimestampTag::GetUid (void)
-{
-  static uint32_t uid = ns3::Tag::AllocateUid<TimestampTag> ("mathieu.paper.TimestampTag");
-  return uid;
-}
-void 
-TimestampTag::Print (std::ostream &os) const
+
+ns3::TypeId 
+TimestampTag::GetTypeId (void)
 {
-  os << ns3::TimeStep (m_creationTime);
+  static ns3::TypeId tid = ns3::TypeId ("anon::TimestampTag")
+    .SetParent<Tag> ()
+    .AddConstructor<TimestampTag> ()
+    .AddAttribute ("CreationTime",
+		   "The time at which the timestamp was created",
+		   ns3::StringValue ("0.0s"),
+		   ns3::MakeTimeAccessor (&TimestampTag::GetTxTime),
+		   ns3::MakeTimeChecker ())
+    ;
+  return tid;
 }
-void 
-TimestampTag::Serialize (ns3::Buffer::Iterator start) const
-{}
-uint32_t 
-TimestampTag::Deserialize (ns3::Buffer::Iterator start)
+ns3::TypeId 
+TimestampTag::GetInstanceTypeId (void) const
 {
-  return 0;
+  return GetTypeId ();
 }
+
 uint32_t 
 TimestampTag::GetSerializedSize (void) const
 {
-  return 0;
+  return 8;
+}
+void 
+TimestampTag::Serialize (ns3::TagBuffer i) const
+{
+  i.WriteU64 (m_creationTime);
+}
+void 
+TimestampTag::Deserialize (ns3::TagBuffer i)
+{
+  m_creationTime = i.ReadU64 ();
 }
 ns3::Time 
 TimestampTag::GetTxTime (void) const
@@ -74,7 +89,7 @@
 {
   TimestampTag tag;
   bool found;
-  found = packet->PeekTag (tag);
+  found = packet->FindFirstMatchingTag (tag);
   if (!found)
     {
       return;
--- a/src/core/config.cc	Thu May 15 11:37:36 2008 -0700
+++ b/src/core/config.cc	Fri May 16 15:52:04 2008 -0700
@@ -765,7 +765,7 @@
   // this should trigger a notification
   d1->SetAttribute ("Source", IntegerValue (-3));
   NS_TEST_ASSERT_EQUAL (m_traceNotification, -3);
-  NS_TEST_ASSERT_EQUAL (m_tracePath, "/NodeA/NodeB/NodesB/1/Source")
+  NS_TEST_ASSERT_EQUAL (m_tracePath, "/NodeA/NodeB/NodesB/1/Source");
   m_traceNotification = 0;
   m_tracePath = "";
   // this should trigger a notification
--- a/src/core/object.cc	Thu May 15 11:37:36 2008 -0700
+++ b/src/core/object.cc	Fri May 16 15:52:04 2008 -0700
@@ -375,7 +375,7 @@
   NS_TEST_ASSERT_UNEQUAL (baseBCopy->GetObject<DerivedA> (), 0);
   NS_TEST_ASSERT_UNEQUAL (baseBCopy->GetObject<BaseA> (), 0);
   NS_TEST_ASSERT_UNEQUAL (baseB->GetObject<DerivedB> (), 0);
-  NS_TEST_ASSERT_UNEQUAL (baseB->GetObject<BaseB> (), 0)
+  NS_TEST_ASSERT_UNEQUAL (baseB->GetObject<BaseB> (), 0);
 
   baseA = CreateObject<BaseA> ();
   baseB = CreateObject<BaseB> ();
--- a/src/core/test.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/core/test.h	Fri May 16 15:52:04 2008 -0700
@@ -100,6 +100,42 @@
 };
 }; // namespace ns3 
 
+#define NS_TEST_ASSERT_EQUAL_FILELINE(got, expected, file, line)    \
+  do {                                                              \
+    if ((got) != (expected))                                        \
+      {                                                             \
+        Failure () << file << ":" <<line                            \
+                   << ": expected " << (expected)                   \
+                   << ", got " << (got) << std::endl;               \
+        result = false;                                             \
+      }                                                             \
+  } while (false)
+
+#define NS_TEST_ASSERT_UNEQUAL_FILELINE(got, expected,file,line)    \
+  do {                                                              \
+    if ((got) == (expected))                                        \
+      {                                                             \
+        Failure () << file << ":" <<line                            \
+                   << ": did not want " << (expected)               \
+                   << ", got " << (got) << std::endl;               \
+        result = false;                                             \
+      }                                                             \
+  } while (false)
+
+
+#define NS_TEST_ASSERT_FILELINE(assertion, file, line)  \
+  do {                                                  \
+    if (!(assertion))                                   \
+      {                                                 \
+        Failure () << file << ":" <<line                \
+                   << ": assertion `" << #assertion     \
+                   << "' failed." << std::endl;         \
+        result = false;                                 \
+      }                                                 \
+  } while (false)
+
+
+
 /**
  * Convenience macro to check that a value returned by a test is what
  * is expected.  Note: this macro assumes a 'bool result = true'
@@ -110,13 +146,8 @@
  * \param expected value that the test is expected to return
  */
 #define NS_TEST_ASSERT_EQUAL(got, expected)             \
-    if ((got) != (expected))                            \
-      {                                                 \
-        Failure () << __FILE__ << ":" <<__LINE__        \
-                   << ": expected " << (expected)       \
-                   << ", got " << (got) << std::endl;   \
-        result = false;                                 \
-      }
+  NS_TEST_ASSERT_EQUAL_FILELINE(got,expected,__FILE__,__LINE__)
+
 /**
  * Convenience macro to check that a value returned by a test is what
  * is expected.  Note: this macro assumes a 'bool result = true'
@@ -127,13 +158,8 @@
  * \param expected value that the test is expected to return
  */
 #define NS_TEST_ASSERT_UNEQUAL(got, expected)           \
-    if ((got) == (expected))                            \
-      {                                                 \
-        Failure () << __FILE__ << ":" <<__LINE__        \
-                   << ": did not want " << (expected)   \
-                   << ", got " << (got) << std::endl;   \
-        result = false;                                 \
-      }
+  NS_TEST_ASSERT_UNEQUAL_FILELINE(got,expected,__FILE__,__LINE__)
+
 /**
  * Convenience macro to check an assertion is held during an unit
  * test.  Note: this macro assumes a 'bool result = true' declaration
@@ -143,13 +169,7 @@
  * \param assertion expression that must be true if the test did not fail
  */
 #define NS_TEST_ASSERT(assertion)                       \
-    if (!(assertion))                                   \
-      {                                                 \
-        Failure () << __FILE__ << ":" <<__LINE__        \
-                   << ": assertion `" << #assertion     \
-                   << "' failed." << std::endl;         \
-        result = false;                                 \
-      }
+  NS_TEST_ASSERT_FILELINE (assertion, __FILE__,__LINE__)
 
 
 #endif /* RUN_SELF_TESTS */
--- a/src/devices/csma/csma-net-device.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/devices/csma/csma-net-device.h	Fri May 16 15:52:04 2008 -0700
@@ -420,7 +420,6 @@
    * fire.
    *
    * @see class CallBackTraceSource
-   * @see class TraceResolver
    */
   TracedCallback<Ptr<const Packet> > m_rxTrace;
   TracedCallback<Ptr<const Packet> > m_dropTrace;
--- a/src/devices/point-to-point/point-to-point-net-device.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/devices/point-to-point/point-to-point-net-device.h	Fri May 16 15:52:04 2008 -0700
@@ -267,7 +267,6 @@
    * fire.
    *
    * @see class CallBackTraceSource
-   * @see class TraceResolver
    */
   TracedCallback<Ptr<const Packet> > m_rxTrace;
   /**
@@ -275,7 +274,6 @@
    * fire.
    *
    * @see class CallBackTraceSource
-   * @see class TraceResolver
    */
   TracedCallback<Ptr<const Packet> > m_dropTrace;
 
--- a/src/devices/wifi/mac-low.cc	Thu May 15 11:37:36 2008 -0700
+++ b/src/devices/wifi/mac-low.cc	Fri May 16 15:52:04 2008 -0700
@@ -40,14 +40,13 @@
 class SnrTag : public Tag
 {
 public:
-  SnrTag ();
-  SnrTag (const SnrTag &o);
-  ~SnrTag ();
-  static uint32_t GetUid (void);
-  void Print (std::ostream &os) const;
-  uint32_t GetSerializedSize (void) const;
-  void Serialize (Buffer::Iterator i) const;
-  uint32_t Deserialize (Buffer::Iterator i);
+
+  static TypeId GetTypeId (void);
+  virtual TypeId GetInstanceTypeId (void) const;
+
+  virtual uint32_t GetSerializedSize (void) const;
+  virtual void Serialize (TagBuffer i) const;
+  virtual void Deserialize (TagBuffer i);
 
   void Set (double snr);
   double Get (void) const;
@@ -55,40 +54,39 @@
   double m_snr;
 };
 
-SnrTag::SnrTag ()
-  : m_snr (0.0)
-{}
-SnrTag::SnrTag (const SnrTag &o)
-  : m_snr (o.m_snr)
-{}
-SnrTag::~SnrTag ()
-{}
-uint32_t 
-SnrTag::GetUid (void)
+TypeId 
+SnrTag::GetTypeId (void)
 {
-  static uint32_t uid = AllocateUid<SnrTag> ("SnrTag.ns3.inria.fr");
-  return uid;
+  static TypeId tid = TypeId ("ns3::SnrTag")
+    .SetParent<Tag> ()
+    .AddConstructor<SnrTag> ()
+    .AddAttribute ("Snr", "The snr of the last packet received",
+                   DoubleValue (0.0),
+                   MakeDoubleAccessor (&SnrTag::Get),
+                   MakeDoubleChecker<double> ())
+    ;
+  return tid;
 }
-void 
-SnrTag::Print (std::ostream &os) const
+TypeId 
+SnrTag::GetInstanceTypeId (void) const
 {
-  os << "snr="<<m_snr;
+  return GetTypeId ();
 }
+
 uint32_t 
 SnrTag::GetSerializedSize (void) const
 {
-  return 0;
+  return sizeof (double);
 }
 void 
-SnrTag::Serialize (Buffer::Iterator i) const
+SnrTag::Serialize (TagBuffer i) const
 {
-  // would need to serialize double to platform-independent format.
+  i.WriteDouble (m_snr);
 }
-uint32_t 
-SnrTag::Deserialize (Buffer::Iterator i)
+void 
+SnrTag::Deserialize (TagBuffer i)
 {
-  // would need to deserialize double from platform-independent format.
-  return 0;
+  m_snr = i.ReadDouble ();
 }
 void 
 SnrTag::Set (double snr)
@@ -472,7 +470,7 @@
     {
       MY_DEBUG ("receive cts from="<<m_currentHdr.GetAddr1 ());
       SnrTag tag;
-      packet->PeekTag (tag);
+      packet->FindFirstMatchingTag (tag);
       WifiRemoteStation *station = GetStation (m_currentHdr.GetAddr1 ());
       station->ReportRxOk (rxSnr, txMode);
       station->ReportRtsOk (rxSnr, txMode, tag.Get ());
@@ -495,7 +493,7 @@
     {
       MY_DEBUG ("receive ack from="<<m_currentHdr.GetAddr1 ());
       SnrTag tag;
-      packet->PeekTag (tag);
+      packet->FindFirstMatchingTag (tag);
       WifiRemoteStation *station = GetStation (m_currentHdr.GetAddr1 ());
       station->ReportRxOk (rxSnr, txMode);
       station->ReportDataOk (rxSnr, txMode, tag.Get ());
--- a/src/devices/wifi/wifi-remote-station-manager.cc	Thu May 15 11:37:36 2008 -0700
+++ b/src/devices/wifi/wifi-remote-station-manager.cc	Fri May 16 15:52:04 2008 -0700
@@ -314,11 +314,11 @@
   WifiMode GetRtsMode (void) const;
   WifiMode GetDataMode (void) const;
 
-  static uint32_t GetUid (void);
-  void Print (std::ostream &os) const;
-  void Serialize (ns3::Buffer::Iterator start) const;
-  uint32_t Deserialize (ns3::Buffer::Iterator start);
-  uint32_t GetSerializedSize (void) const;
+  static TypeId GetTypeId (void);
+  virtual TypeId GetInstanceTypeId (void) const;
+  virtual uint32_t GetSerializedSize (void) const;
+  virtual void Serialize (TagBuffer i) const;
+  virtual void Deserialize (TagBuffer i);
 private:
   WifiMode m_rtsMode;
   WifiMode m_dataMode;
@@ -340,30 +340,46 @@
 {
   return m_dataMode;
 }
-
-uint32_t 
-TxModeTag::GetUid (void)
-{
-  static uint32_t uid = Tag::AllocateUid<TxModeTag> ("ns3.wifi.TxModeTag");
-  return uid;
-}
-void 
-TxModeTag::Print (std::ostream &os) const
+TypeId 
+TxModeTag::GetTypeId (void)
 {
-  os << "rts="<<m_rtsMode<<" data="<<m_dataMode;
+  static TypeId tid = TypeId ("ns3::TxModeTag")
+    .SetParent<Tag> ()
+    .AddConstructor<TxModeTag> ()
+    .AddAttribute ("RtsTxMode", 
+                   "Tx mode of rts to use later",
+                   EmptyAttributeValue (),
+                   MakeWifiModeAccessor (&TxModeTag::GetRtsMode),
+                   MakeWifiModeChecker ())
+    .AddAttribute ("DataTxMode", 
+                   "Tx mode of data to use later",
+                   EmptyAttributeValue (),
+                   MakeWifiModeAccessor (&TxModeTag::GetDataMode),
+                   MakeWifiModeChecker ())
+    ;
+  return tid;
 }
-void 
-TxModeTag::Serialize (ns3::Buffer::Iterator start) const
-{}
-uint32_t 
-TxModeTag::Deserialize (ns3::Buffer::Iterator start)
+TypeId 
+TxModeTag::GetInstanceTypeId (void) const
 {
-  return 0;
+  return GetTypeId ();
 }
 uint32_t 
 TxModeTag::GetSerializedSize (void) const
 {
-  return 0;
+  return sizeof (WifiMode) * 2;
+}
+void 
+TxModeTag::Serialize (TagBuffer i) const
+{
+  i.Write ((uint8_t *)&m_rtsMode, sizeof (WifiMode));
+  i.Write ((uint8_t *)&m_dataMode, sizeof (WifiMode));
+}
+void 
+TxModeTag::Deserialize (TagBuffer i)
+{
+  i.Read ((uint8_t *)&m_rtsMode, sizeof (WifiMode));
+  i.Read ((uint8_t *)&m_dataMode, sizeof (WifiMode));
 }
 
 } // namespace ns3
@@ -546,7 +562,7 @@
     }
   TxModeTag tag;
   bool found;
-  found = packet->PeekTag (tag);
+  found = packet->FindFirstMatchingTag (tag);
   NS_ASSERT (found);
   return tag.GetDataMode ();
 }
@@ -559,7 +575,7 @@
     }
   TxModeTag tag;
   bool found;
-  found = packet->PeekTag (tag);
+  found = packet->FindFirstMatchingTag (tag);
   NS_ASSERT (found);
   return tag.GetRtsMode ();
 }
--- a/src/helper/mobility-helper.cc	Thu May 15 11:37:36 2008 -0700
+++ b/src/helper/mobility-helper.cc	Fri May 16 15:52:04 2008 -0700
@@ -19,7 +19,6 @@
  */
 #include "ns3/mobility-helper.h"
 #include "ns3/mobility-model.h"
-#include "ns3/mobility-model-notifier.h"
 #include "ns3/position-allocator.h"
 #include "ns3/hierarchical-mobility-model.h"
 #include "ns3/log.h"
@@ -30,7 +29,6 @@
 NS_LOG_COMPONENT_DEFINE ("MobilityHelper");
 
 MobilityHelper::MobilityHelper ()
-  : m_notifierEnabled (false)
 {
   m_position = CreateObject<RandomRectanglePositionAllocator> 
     ("X", RandomVariableValue (ConstantVariable (0.0)),
@@ -40,16 +38,6 @@
 MobilityHelper::~MobilityHelper ()
 {}
 void 
-MobilityHelper::EnableNotifier (void)
-{
-  m_notifierEnabled = true;
-}
-void 
-MobilityHelper::DisableNotifier (void)
-{
-  m_notifierEnabled = false;
-}
-void 
 MobilityHelper::SetPositionAllocator (Ptr<PositionAllocator> allocator)
 {
   m_position = allocator;
@@ -156,15 +144,6 @@
 	}
       Vector position = m_position->GetNext ();
       model->SetPosition (position);
-      if (m_notifierEnabled)
-	{
-	  Ptr<MobilityModelNotifier> notifier = 
-	    object->GetObject<MobilityModelNotifier> ();
-	  if (notifier == 0)
-	    {
-	      object->AggregateObject (CreateObject<MobilityModelNotifier> ());
-	    }
-	}
     }
 }
 
--- a/src/helper/mobility-helper.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/helper/mobility-helper.h	Fri May 16 15:52:04 2008 -0700
@@ -43,20 +43,6 @@
   ~MobilityHelper ();
 
   /**
-   * After this method is called, every call to MobilityHelper::Install
-   * will also attach to the new ns3::MobilityModel an ns3::MobilityModelNotifier
-   * which can be used to listen to CourseChange events.
-   */
-  void EnableNotifier (void);
-  /**
-   * After this method is called, no ns3::MobilityModelNotifier object will
-   * be associated to any new ns3::MobilityModel created by MobilityHelper::Install.
-   * This will make it impossible to listen to "CourseChange" events from these
-   * new ns3::MobilityModel instances.
-   */
-  void DisableNotifier (void);
-
-  /**
    * \param allocator allocate initial node positions
    *
    * Set the position allocator which will be used to allocate
@@ -169,9 +155,6 @@
    * subclass (the type of which was set with MobilityHelper::SetMobilityModel), 
    * aggregates it to the mode, and sets an initial position based on the current 
    * position allocator (set through MobilityHelper::SetPositionAllocator). 
-   * Optionally, this method will also create and aggregate a
-   * ns3::MobilityModelNotifier to generate 'CourseChange' events based on the 
-   * boolean flag set by MobilityHelper::EnableNotifierAll and MobilityHelper::DisableNotifier.
    */
   void Install (NodeContainer container);
 
@@ -183,7 +166,6 @@
 private:
 
   std::vector<Ptr<MobilityModel> > m_mobilityStack;
-  bool m_notifierEnabled;
   ObjectFactory m_mobility;
   Ptr<PositionAllocator> m_position;
 };
--- a/src/helper/ns2-mobility-helper.cc	Thu May 15 11:37:36 2008 -0700
+++ b/src/helper/ns2-mobility-helper.cc	Fri May 16 15:52:04 2008 -0700
@@ -24,7 +24,6 @@
 #include "ns3/node-list.h"
 #include "ns3/node.h"
 #include "ns3/static-speed-mobility-model.h"
-#include "ns3/mobility-model-notifier.h"
 #include "ns2-mobility-helper.h"
 
 NS_LOG_COMPONENT_DEFINE ("Ns2MobilityHelper");
@@ -36,17 +35,6 @@
   : m_filename (filename)
 {}
 
-void 
-Ns2MobilityHelper::EnableNotifier (void)
-{
-  m_notifierEnabled = true;
-}
-void 
-Ns2MobilityHelper::DisableNotifier (void)
-{
-  m_notifierEnabled = false;
-}
-
 
 
 Ptr<StaticSpeedMobilityModel>
@@ -67,12 +55,6 @@
       model = CreateObject<StaticSpeedMobilityModel> ();
       object->AggregateObject (model);
     }
-  Ptr<MobilityModelNotifier> notifier = object->GetObject<MobilityModelNotifier> ();
-  if (notifier == 0)
-    {
-      notifier = CreateObject<MobilityModelNotifier> ();
-      object->AggregateObject (notifier);
-    }
   return model;
 }
 
--- a/src/helper/ns2-mobility-helper.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/helper/ns2-mobility-helper.h	Fri May 16 15:52:04 2008 -0700
@@ -42,9 +42,6 @@
    */
   Ns2MobilityHelper (std::string filename);
 
-  void EnableNotifier (void);
-  void DisableNotifier (void);
-
   /**
    * Read the ns2 trace file and configure the movement
    * patterns of all nodes contained in the global ns3::NodeList
@@ -77,7 +74,6 @@
   Ptr<StaticSpeedMobilityModel> GetMobilityModel (std::string idString, const ObjectStore &store) const;
   double ReadDouble (std::string valueString) const;
   std::string m_filename;
-  bool m_notifierEnabled;
 };
 
 } // namespace ns3
--- a/src/internet-node/arp-l3-protocol.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/internet-node/arp-l3-protocol.h	Fri May 16 15:52:04 2008 -0700
@@ -31,7 +31,7 @@
 class NetDevice;
 class Node;
 class Packet;
-class TraceContext;
+
 /**
  * \brief An implementation of the ARP protocol
  */
--- a/src/internet-node/ascii-trace.cc	Thu May 15 11:37:36 2008 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/* -*-	Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- *
- * 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 "ascii-trace.h"
-
-#include "ns3/config.h"
-#include "ns3/simulator.h"
-#include "ns3/node.h"
-#include "ns3/packet.h"
-#include "ns3/queue.h"
-
-namespace ns3 {
-
-AsciiTrace::AsciiTrace (std::string filename)
-{
-  m_os.open (filename.c_str ());
-}
-AsciiTrace::~AsciiTrace ()
-{
-  m_os.close ();
-}
-void
-AsciiTrace::TraceAllQueues (void)
-{
-  Packet::EnableMetadata ();
-  Config::Connect ("/NodeList/*/DeviceList/*/TxQueue/Enqueue",
-                              MakeCallback (&AsciiTrace::LogDevQueueEnqueue, this));
-  Config::Connect ("/NodeList/*/DeviceList/*/TxQueue/Dequeue",
-                              MakeCallback (&AsciiTrace::LogDevQueueDequeue, this));
-  Config::Connect ("/NodeList/*/DeviceList/*/TxQueue/Drop",
-                              MakeCallback (&AsciiTrace::LogDevQueueDrop, this));
-}
-void
-AsciiTrace::TraceAllNetDeviceRx (void)
-{
-  Packet::EnableMetadata ();
-  Config::Connect ("/NodeList/*/DeviceList/*/Rx",
-                              MakeCallback (&AsciiTrace::LogDevRx, this));
-}
-
-void 
-AsciiTrace::LogDevQueueEnqueue (std::string context,
-                                Ptr<const Packet> packet)
-{
-  m_os << "+ ";
-  m_os << Simulator::Now ().GetSeconds () << " ";
-  m_os << context;
-  m_os << " pkt-uid=" << packet->GetUid () << " ";
-  packet->Print (m_os);
-  m_os << std::endl;
-}
-
-void 
-AsciiTrace::LogDevQueueDequeue (std::string context,
-                                Ptr<const Packet> packet)
-{
-  m_os << "- ";
-  m_os << Simulator::Now ().GetSeconds () << " ";
-  m_os << context;
-  m_os << " pkt-uid=" << packet->GetUid () << " ";
-  packet->Print (m_os);
-  m_os << std::endl;
-}
-
-void 
-AsciiTrace::LogDevQueueDrop (std::string context,
-                             Ptr<const Packet> packet)
-{
-  m_os << "d ";
-  m_os << Simulator::Now ().GetSeconds () << " ";
-  m_os << context;
-  m_os << " pkt-uid=" << packet->GetUid () << " ";
-  packet->Print (m_os);
-  m_os << std::endl;
-}
-void 
-AsciiTrace::LogDevRx (std::string context,
-                      Ptr<const Packet> p)
-{
-  m_os << "r " << Simulator::Now ().GetSeconds () << " ";
-  m_os << context;
-  m_os << " pkt-uid=" << p->GetUid () << " ";
-  p->Print (m_os);
-  m_os << std::endl;  
-}
-
-}//namespace ns3
--- a/src/internet-node/ascii-trace.h	Thu May 15 11:37:36 2008 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/* -*-	Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- *
- * 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 ASCII_TRACE_H
-#define ASCII_TRACE_H
-
-#include <string>
-#include <fstream>
-#include "ns3/ptr.h"
-
-namespace ns3 {
-
-class Packet;
-class TraceContext;
-
-class AsciiTrace 
-{
-public:
-  AsciiTrace (std::string filename);
-  ~AsciiTrace ();
-  void TraceAllQueues (void);
-  void TraceAllNetDeviceRx (void);
-private:
-  void LogDevQueueEnqueue (std::string context, Ptr<const Packet> p);
-  void LogDevQueueDequeue (std::string context, Ptr<const Packet> p);
-  void LogDevQueueDrop (std::string context, Ptr<const Packet> p);
-  void LogDevRx (std::string context, Ptr<const Packet> p);
-  std::ofstream m_os;
-};
-
-}//namespace ns3
-
-#endif /* ASCII_TRACE_H */
--- a/src/internet-node/ipv4-interface.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/internet-node/ipv4-interface.h	Fri May 16 15:52:04 2008 -0700
@@ -31,7 +31,6 @@
 
 class NetDevice;
 class Packet;
-class TraceContext;
 
 /**
  * \brief The IPv4 representation of a network interface
--- a/src/internet-node/ipv4-l4-demux.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/internet-node/ipv4-l4-demux.h	Fri May 16 15:52:04 2008 -0700
@@ -32,7 +32,6 @@
 
 class Ipv4L4Protocol;
 class Node;
-class TraceContext;
 
 /**
  * \brief L4 Ipv4 Demux
--- a/src/internet-node/ipv4-l4-protocol.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/internet-node/ipv4-l4-protocol.h	Fri May 16 15:52:04 2008 -0700
@@ -31,8 +31,6 @@
 
 class Packet;
 class Ipv4Address;
-class TraceResolver;
-class TraceContext;
 
 /**
  * \brief L4 Protocol base class 
--- a/src/internet-node/pcap-trace.cc	Thu May 15 11:37:36 2008 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-/* -*-	Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- *
- * 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 "pcap-trace.h"
-
-#include <sstream>
-
-#include "ns3/config.h"
-#include "ns3/callback.h"
-#include "ns3/pcap-writer.h"
-#include "ns3/node-list.h"
-#include "ns3/node.h"
-#include "ns3/packet.h"
-#include "ns3/log.h"
-
-#include "ipv4-l3-protocol.h"
-
-NS_LOG_COMPONENT_DEFINE ("PcapTrace");
-
-namespace ns3 {
-
-
-PcapTrace::PcapTrace (std::string filename)
-  : m_filename (filename)
-{}
-PcapTrace::~PcapTrace ()
-{
-  for (std::vector<Trace>::iterator i = m_traces.begin ();
-       i != m_traces.end (); i++)
-    {
-      delete i->writer;
-    }
-}
-
-void 
-PcapTrace::TraceAllIp (void)
-{
-  Config::Connect ("/NodeList/*/$ns3::Ipv4L3Protocol/Tx",
-                              MakeCallback (&PcapTrace::LogTxIp, this));
-  Config::Connect ("/NodeList/*/$ns3::Ipv4L3Protocol/Rx",
-                              MakeCallback (&PcapTrace::LogRxIp, this));
-}
-
-PcapWriter *
-PcapTrace::GetStream (uint32_t nodeId, uint32_t interfaceId)
-{
-  for (std::vector<Trace>::iterator i = m_traces.begin ();
-       i != m_traces.end (); i++)
-    {
-      if (i->nodeId == nodeId &&
-	  i->interfaceId == interfaceId)
-	{
-	  return i->writer;
-	}
-    }
-  PcapTrace::Trace trace;
-  trace.nodeId = nodeId;
-  trace.interfaceId = interfaceId;
-  trace.writer = new PcapWriter ();
-  std::ostringstream oss;
-  oss << m_filename << "-" << nodeId << "-" << interfaceId;
-  std::string filename = oss.str ();
-  trace.writer->Open (filename);
-  trace.writer->WriteIpHeader ();
-  m_traces.push_back (trace);
-  return trace.writer;
-}
-
-uint32_t
-PcapTrace::GetNodeIndex (std::string context) const
-{
-  std::string::size_type pos;
-  pos = context.find ("/NodeList/");
-  NS_ASSERT (pos == 0);
-  std::string::size_type afterNodeIndex = context.find ("/", 11);
-  NS_ASSERT (afterNodeIndex != std::string::npos);
-  std::string index = context.substr (10, afterNodeIndex - 10);
-  NS_LOG_DEBUG ("index="<<index);
-  std::istringstream iss;
-  iss.str (index);
-  uint32_t nodeIndex;
-  iss >> nodeIndex;
-  return nodeIndex;
-}  
-
-void 
-PcapTrace::LogTxIp (std::string context, Ptr<const Packet> p, uint32_t interfaceIndex)
-{
-  PcapWriter *writer = GetStream (GetNodeIndex (context), interfaceIndex);
-  writer->WritePacket (p);
-}
-
-void 
-PcapTrace::LogRxIp (std::string context, Ptr<const Packet> p, uint32_t interfaceIndex)
-{
-  PcapWriter *writer = GetStream (GetNodeIndex (context), interfaceIndex);
-  writer->WritePacket (p);
-}
-
-
-}//namespace ns3
--- a/src/internet-node/pcap-trace.h	Thu May 15 11:37:36 2008 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/* -*-	Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- *
- * 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 PCAP_TRACE_H
-#define PCAP_TRACE_H
-
-#include <string>
-#include <vector>
-#include "ns3/ptr.h"
-
-namespace ns3 {
-
-class Packet;
-class TraceContext;
-class PcapWriter;
-
-class PcapTrace 
-{
-public:
-  PcapTrace (std::string filename);
-  ~PcapTrace ();
-
-  void TraceAllIp (void);
-private:
-  PcapWriter *GetStream (uint32_t nodeId, uint32_t interfaceId);
-  void LogRxIp (std::string context, Ptr<const Packet> p, uint32_t interfaceIndex);
-  void LogTxIp (std::string context, Ptr<const Packet> p, uint32_t interfaceIndex);
-  uint32_t GetNodeIndex (std::string context) const;
-  std::string m_filename;
-  struct Trace {
-    uint32_t nodeId;
-    uint32_t interfaceId;
-    PcapWriter *writer;
-  };
-  std::vector<Trace> m_traces;
-};
-
-}//namespace ns3
-
-#endif /* PCAP_TRACE_H */
--- a/src/internet-node/tcp-l4-protocol.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/internet-node/tcp-l4-protocol.h	Fri May 16 15:52:04 2008 -0700
@@ -37,7 +37,6 @@
 namespace ns3 {
 
 class Node;
-class TraceContext;
 class Socket;
 class TcpHeader;
 /**
--- a/src/internet-node/udp-l4-protocol.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/internet-node/udp-l4-protocol.h	Fri May 16 15:52:04 2008 -0700
@@ -32,7 +32,6 @@
 namespace ns3 {
 
 class Node;
-class TraceContext;
 class Socket;
 /**
  * \brief Implementation of the UDP protocol
--- a/src/internet-node/wscript	Thu May 15 11:37:36 2008 -0700
+++ b/src/internet-node/wscript	Fri May 16 15:52:04 2008 -0700
@@ -26,8 +26,6 @@
         'tcp-socket.cc',
         'ipv4-end-point-demux.cc',
         'ipv4-impl.cc',
-        'ascii-trace.cc',
-        'pcap-trace.cc',
         'udp-impl.cc',
         'tcp-impl.cc',
         'pending-data.cc',
@@ -39,8 +37,6 @@
     headers.module = 'internet-node'
     headers.source = [
         'internet-stack.h',
-        'ascii-trace.h',
-        'pcap-trace.h',
         'ipv4-header.h',
         'udp-header.h',
         'tcp-header.h',
--- a/src/mobility/hierarchical-mobility-model.cc	Thu May 15 11:37:36 2008 -0700
+++ b/src/mobility/hierarchical-mobility-model.cc	Fri May 16 15:52:04 2008 -0700
@@ -18,7 +18,6 @@
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
 #include "hierarchical-mobility-model.h"
-#include "mobility-model-notifier.h"
 #include "ns3/pointer.h"
 
 namespace ns3 {
@@ -54,28 +53,14 @@
 HierarchicalMobilityModel::SetChild (Ptr<MobilityModel> model)
 {
   m_child = model;
-  Ptr<MobilityModelNotifier> notifier = 
-    m_child->GetObject<MobilityModelNotifier> ();
-  if (notifier == 0)
-    {
-      notifier = CreateObject<MobilityModelNotifier> ();
-      m_child->AggregateObject (notifier);
-    }
-  notifier->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ChildChanged, this));
+  m_child->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ChildChanged, this));
 }
 
 void 
 HierarchicalMobilityModel::SetParent (Ptr<MobilityModel> model)
 {
   m_parent = model;
-  Ptr<MobilityModelNotifier> notifier = 
-    m_parent->GetObject<MobilityModelNotifier> ();
-  if (notifier == 0)
-    {
-      notifier = CreateObject<MobilityModelNotifier> ();
-      m_parent->AggregateObject (notifier);
-    }
-  notifier->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ParentChanged, this));
+  m_parent->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ParentChanged, this));
 }
 
 
--- a/src/mobility/mobility-model-notifier.cc	Thu May 15 11:37:36 2008 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- *
- * 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 "mobility-model-notifier.h"
-#include "ns3/trace-source-accessor.h"
-
-namespace ns3 {
-
-TypeId 
-MobilityModelNotifier::GetTypeId (void)
-{
-  static TypeId tid = TypeId ("MobilityModelNotifier")
-    .SetParent<Object> ()
-    .AddConstructor<MobilityModelNotifier> ()
-    .AddTraceSource ("CourseChange", 
-                     "The value of the position and/or velocity vector changed",
-                     MakeTraceSourceAccessor (&MobilityModelNotifier::m_trace))
-    ;
-  return tid;
-}
-
-MobilityModelNotifier::MobilityModelNotifier ()
-{}
-
-void 
-MobilityModelNotifier::Notify (Ptr<const MobilityModel> position) const
-{
-  m_trace (position);
-}
-
-} // namespace ns3
--- a/src/mobility/mobility-model-notifier.h	Thu May 15 11:37:36 2008 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- *
- * 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 MOBILITY_MODEL_NOTIFIER_H
-#define MOBILITY_MODEL_NOTIFIER_H
-
-#include "ns3/object.h"
-#include "ns3/callback.h"
-#include "ns3/traced-callback.h"
-#include "mobility-model.h"
-
-namespace ns3 {
-
-/**
- * \brief notify listeners of position changes.
- */
-class MobilityModelNotifier : public Object
-{
-public:
-  static TypeId GetTypeId (void);
-
-  /**
-   * Create a new position notifier
-   */
-  MobilityModelNotifier ();
-
-  /**
-   * \param position the position which just changed.
-   */
-  void Notify (Ptr<const MobilityModel> position) const;
-private:
-  TracedCallback<Ptr<const MobilityModel> > m_trace;
-};
-
-} // namespace ns3
-
-#endif /* MOBILITY_MODEL_NOTIFIER_H */
--- a/src/mobility/mobility-model.cc	Thu May 15 11:37:36 2008 -0700
+++ b/src/mobility/mobility-model.cc	Fri May 16 15:52:04 2008 -0700
@@ -17,9 +17,11 @@
  *
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
+
+#include <math.h>
+
 #include "mobility-model.h"
-#include "mobility-model-notifier.h"
-#include <math.h>
+#include "ns3/trace-source-accessor.h"
 
 namespace ns3 {
 
@@ -39,6 +41,9 @@
                    VectorValue (Vector (0.0, 0.0, 0.0)), // ignored initial value.
                    MakeVectorAccessor (&MobilityModel::GetVelocity),
                    MakeVectorChecker ())
+    .AddTraceSource ("CourseChange", 
+                     "The value of the position and/or velocity vector changed",
+                     MakeTraceSourceAccessor (&MobilityModel::m_courseChangeTrace))
     ;
   return tid;
 }
@@ -77,11 +82,7 @@
 void
 MobilityModel::NotifyCourseChange (void) const
 {
-  Ptr<MobilityModelNotifier> notifier = GetObject<MobilityModelNotifier> ();
-  if (notifier != 0)
-    {
-      notifier->Notify (this);
-    }
+  m_courseChangeTrace(this);
 }
 
 } // namespace ns3
--- a/src/mobility/mobility-model.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/mobility/mobility-model.h	Fri May 16 15:52:04 2008 -0700
@@ -20,8 +20,10 @@
 #ifndef MOBILITY_MODEL_H
 #define MOBILITY_MODEL_H
 
+#include "vector.h"
+
 #include "ns3/object.h"
-#include "vector.h"
+#include "ns3/traced-callback.h"
 
 namespace ns3 {
 
@@ -84,6 +86,13 @@
    * implement this method.
    */
   virtual Vector DoGetVelocity (void) const = 0;
+
+  /**
+   * Used to alert subscribers that a change in direction, velocity,
+   * or position has occurred.
+   */
+  TracedCallback<Ptr<const MobilityModel> > m_courseChangeTrace;
+
 };
 
 }; // namespace ns3
--- a/src/mobility/mobility.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/mobility/mobility.h	Fri May 16 15:52:04 2008 -0700
@@ -5,8 +5,8 @@
  *  - a set of mobility models which are used to track and maintain
  *    the "current" cartesian position and speed of an object.
  *
- *  - a "course change notifier" which can be used to register listeners
- *    to the course changes of a mobility model: ns3::MobilityModelNotifier.
+ *  - a "course change notifier" trace which can be used to register
+ *    listeners to the course changes of a mobility model
  *
  * The mobility models themselves are:
  *   - ns3::StaticMobilityModel: a model which maintains a constant position
--- a/src/mobility/wscript	Thu May 15 11:37:36 2008 -0700
+++ b/src/mobility/wscript	Fri May 16 15:52:04 2008 -0700
@@ -6,7 +6,6 @@
         'vector.cc',
         'hierarchical-mobility-model.cc',
         'mobility-model.cc',
-        'mobility-model-notifier.cc',
         'position-allocator.cc',
         'rectangle.cc',
         'static-mobility-model.cc',
@@ -23,7 +22,6 @@
         'vector.h',
         'hierarchical-mobility-model.h',
         'mobility-model.h',
-        'mobility-model-notifier.h',
         'position-allocator.h',
         'rectangle.h',
         'static-mobility-model.h',
--- a/src/node/net-device.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/node/net-device.h	Fri May 16 15:52:04 2008 -0700
@@ -32,7 +32,6 @@
 namespace ns3 {
 
 class Node;
-class TraceContext;
 class Channel;
 class Packet;
 
--- a/src/node/node.cc	Thu May 15 11:37:36 2008 -0700
+++ b/src/node/node.cc	Fri May 16 15:52:04 2008 -0700
@@ -186,6 +186,11 @@
                          uint16_t protocol, const Address &from)
 {
   bool found = false;
+  // if there are (potentially) multiple handlers, we need to copy the
+  // packet before passing it to each handler, because handlers may
+  // modify it.
+  bool copyNeeded = (m_handlers.size () > 1);
+
   for (ProtocolHandlerList::iterator i = m_handlers.begin ();
        i != m_handlers.end (); i++)
     {
@@ -195,7 +200,7 @@
           if (i->protocol == 0 || 
               i->protocol == protocol)
             {
-              i->handler (device, packet, protocol, from);
+              i->handler (device, (copyNeeded ? packet->Copy () : packet), protocol, from);
               found = true;
             }
         }
--- a/src/node/node.h	Thu May 15 11:37:36 2008 -0700
+++ b/src/node/node.h	Fri May 16 15:52:04 2008 -0700
@@ -29,7 +29,6 @@
 
 namespace ns3 {
 
-class TraceContext;
 class NetDevice;
 class Application;
 class Packet;
--- a/src/node/packet-socket.cc	Thu May 15 11:37:36 2008 -0700
+++ b/src/node/packet-socket.cc	Fri May 16 15:52:04 2008 -0700
@@ -111,11 +111,11 @@
   Ptr<NetDevice> dev ;
   if (address.IsSingleDevice ())
     {
-      dev = 0;
+      dev = m_node->GetDevice (address.GetSingleDevice ());
     }
   else
     {
-      dev = m_node->GetDevice (address.GetSingleDevice ());
+      dev = 0;
     }
   m_node->RegisterProtocolHandler (MakeCallback (&PacketSocket::ForwardUp, this),
                                    address.GetProtocol (), dev);
--- a/src/routing/global-routing/global-router-interface.cc	Thu May 15 11:37:36 2008 -0700
+++ b/src/routing/global-routing/global-router-interface.cc	Fri May 16 15:52:04 2008 -0700
@@ -533,6 +533,21 @@
     {
       Ptr<NetDevice> ndLocal = node->GetDevice(i);
 
+      // Check if it is an IP interface (could be a pure L2 NetDevice)
+      bool isIp = false;
+      for (uint32_t i = 0; i < ipv4Local->GetNInterfaces (); ++i )
+        {
+          if (ipv4Local->GetNetDevice (i) == ndLocal) 
+            {
+              isIp = true;
+              break;
+            }
+        }
+      if (!isIp)
+        {
+          continue;
+        }
+
       if (ndLocal->IsBroadcast () && !ndLocal->IsPointToPoint () )
         {
           NS_LOG_LOGIC ("Broadcast link");
@@ -623,6 +638,10 @@
 // router (to use OSPF lingo) is running.  
 //
           Ptr<Channel> ch = ndLocal->GetChannel();
+          if (ch == NULL)
+            {
+              continue;
+            }
           Ptr<NetDevice> ndRemote = GetAdjacent(ndLocal, ch);
 //
 // The adjacent net device is aggregated to a node.  We need to ask that net 
--- a/utils/bench-packets.cc	Thu May 15 11:37:36 2008 -0700
+++ b/utils/bench-packets.cc	Fri May 16 15:52:04 2008 -0700
@@ -22,6 +22,7 @@
 #include "ns3/packet-metadata.h"
 #include <iostream>
 #include <sstream>
+#include <string>
 
 using namespace ns3;
 
@@ -39,6 +40,7 @@
   virtual void Serialize (Buffer::Iterator start) const;
   virtual uint32_t Deserialize (Buffer::Iterator start);
 private:
+  static std::string GetTypeName (void);
   bool m_ok;
 };
 
@@ -55,12 +57,19 @@
 }
 
 template <int N>
+std::string 
+BenchHeader<N>::GetTypeName (void)
+{
+  std::ostringstream oss;
+  oss << "ns3::BenchHeader<" << N << ">";
+  return oss.str ();
+}
+
+template <int N>
 TypeId 
 BenchHeader<N>::GetTypeId (void)
 {
-  std::ostringstream oss;
-  oss << "ns3::BenchHeader<"<<N<<">";
-  static TypeId tid = TypeId (oss.str ().c_str ())
+  static TypeId tid = TypeId (GetTypeName ().c_str ())
     .SetParent<Header> ()
     ;
   return tid;
@@ -105,10 +114,72 @@
   return N;
 }
 
+template <int N>
+class BenchTag : public Tag
+{
+public:
+  static std::string GetName (void) {
+    std::ostringstream oss;
+    oss << "anon::BenchTag<" << N << ">";
+    return oss.str ();
+  }
+  static TypeId GetTypeId (void) {
+    static TypeId tid = TypeId (GetName ().c_str ())
+      .SetParent<Tag> ()
+      .AddConstructor<BenchTag > ()
+      .HideFromDocumentation ()
+      ;
+    return tid;
+  }
+  virtual TypeId GetInstanceTypeId (void) const {
+    return GetTypeId ();
+  }
+  virtual uint32_t GetSerializedSize (void) const {
+    return N;
+  }
+  virtual void Serialize (TagBuffer buf) const {
+    for (uint32_t i = 0; i < N; ++i)
+      {
+        buf.WriteU8 (N);
+      }
+  }
+  virtual void Deserialize (TagBuffer buf) {
+    for (uint32_t i = 0; i < N; ++i)
+      {
+        buf.ReadU8 ();
+      }
+  }
+  BenchTag ()
+    : Tag () {}
+};
 
 
 static void 
-benchPtrA (uint32_t n)
+benchD (uint32_t n)
+{
+  BenchHeader<25> ipv4;
+  BenchHeader<8> udp;
+  BenchTag<16> tag1;
+  BenchTag<17> tag2;
+
+  for (uint32_t i = 0; i < n; i++) {
+    Ptr<Packet> p = Create<Packet> (2000);
+    p->AddTag (tag1);
+    p->AddHeader (udp);
+    p->FindFirstMatchingTag (tag1);
+    p->AddTag (tag2);
+    p->AddHeader (ipv4);
+    Ptr<Packet> o = p->Copy ();
+    o->RemoveHeader (ipv4);
+    p->FindFirstMatchingTag (tag2);
+    o->RemoveHeader (udp);
+  }
+}
+
+
+
+static void 
+benchA (uint32_t n)
 {
   BenchHeader<25> ipv4;
   BenchHeader<8> udp;
@@ -124,7 +195,7 @@
 }
 
 static void 
-benchPtrB (uint32_t n)
+benchB (uint32_t n)
 {
   BenchHeader<25> ipv4;
   BenchHeader<8> udp;
@@ -137,7 +208,7 @@
 }
 
 static void
-ptrC2 (Ptr<Packet> p)
+C2 (Ptr<Packet> p)
 {
   BenchHeader<8> udp;
 
@@ -145,15 +216,15 @@
 }
 
 static void 
-ptrC1 (Ptr<Packet> p)
+C1 (Ptr<Packet> p)
 {
   BenchHeader<25> ipv4;
   p->RemoveHeader (ipv4);
-  ptrC2 (p);
+  C2 (p);
 }
 
 static void
-benchPtrC (uint32_t n)
+benchC (uint32_t n)
 {
   BenchHeader<25> ipv4;
   BenchHeader<8> udp;
@@ -162,28 +233,10 @@
     Ptr<Packet> p = Create<Packet> (2000);
     p->AddHeader (udp);
     p->AddHeader (ipv4);
-    ptrC1 (p);
+    C1 (p);
   }
 }
 
-#if 0
-static void
-benchPrint (uint32_t n)
-{
-  PacketPrinter printer;
-  BenchHeader<25> ipv4;
-  BenchHeader<8> udp;
-  Ptr<Packet> p = Create<Packet> (2000);
-  p->AddHeader (udp);
-  p->AddHeader (ipv4);
-
-  for (uint32_t i = 0; i < n; i++) 
-    {
-      p->Print (std::cerr, printer);
-    }  
-}
-#endif
-
 
 static void
 runBench (void (*bench) (uint32_t), uint32_t n, char const *name)
@@ -218,15 +271,17 @@
     }
   std::cout << "Running bench-packets with n=" << n << std::endl;
 
-  Packet::EnableMetadata ();
-  runBench (&benchPtrA, n, "a");
-  runBench (&benchPtrB, n, "b");
-  runBench (&benchPtrC, n, "c");
+  runBench (&benchA, n, "a");
+  runBench (&benchB, n, "b");
+  runBench (&benchC, n, "c");
+  runBench (&benchD, n, "d");
 
-  //runBench (&benchPrint, n, "print");
-  runBench (&benchPtrA, n, "meta-a");
-  runBench (&benchPtrB, n, "meta-b");
-  runBench (&benchPtrC, n, "meta-c");
+  Packet::EnableMetadata ();
+  runBench (&benchA, n, "meta-a");
+  runBench (&benchB, n, "meta-b");
+  runBench (&benchC, n, "meta-c");
+  runBench (&benchD, n, "meta-d");
+
 
 
   return 0;