HOWTO create a new type of protocol header or trailer

From Nsnam
Jump to: navigation, search

Main Page - Current Development - Developer FAQ - Tools - Related Projects - Project Ideas - Summer Projects

Installation - Troubleshooting - User FAQ - HOWTOs - Samples - Models - Education - Contributed Code - Papers

At some point you may wish to create a new or existing protocol which is currently not implemented in ns-3. This protocol will likely require a new type of header. Creating a new header or trailer for this protocol is relatively straightforward and requires subclassing the ns3::Header class described below.

HOWTO create a new type of protocol header or trailer

The key is to implement a new subclass of the ns3::Header base class to represent your protocol header:

   class YHeader : public Header
   {
   public:
     // must be implemented to become a valid new header.
     static TypeId GetTypeId (void);
     virtual TypeId GetInstanceTypeId (void) const;
     virtual uint32_t GetSerializedSize (void) const;
     virtual void Serialize (Buffer::Iterator start) const;
     virtual uint32_t Deserialize (Buffer::Iterator start);
     virtual void Print (std::ostream &os) const;
     // allow protocol-specific access to the header data.
     void SetData (uint32_t data);
     uint32_t GetData (void) const;
   private:
     uint32_t m_data;
   };

Once this class is implemented, you can easily store your protocol header into a packet:

   Ptr<Packet> p = ...;
   YHeader yHeader;
   yHeader.SetData (0xdeadbeaf);
   // copy the header into the packet
   p->AddHeader (yHeader);

and get it out of a packet:

   Ptr<Packet> p = ...;
   YHeader yHeader;
   // copy the header from the packet
   p->RemoveHeader (yHeader);
   uint32_t data = yHeader.GetData ();

The implementation of the new header is very simple. First, you need to give a TypeId to your YHeader class:

   TypeId
   YHeader::GetTypeId (void)
   {
     static TypeId tid = TypeId ("YHeader")
       .SetParent<Header> ()
       .AddConstructor<YHeader> ()
     ;
     return tid;
   }
   TypeId
   YHeader::GetInstanceTypeId (void)
   {
     return GetTypeId ();
   }

Then, you need to allow your header to serialize and deserialize itself to a byte buffer in its network representation. Here, our new protocol header contains first a 2-byte constant, and, then, the data field so, the total size of the header is 2+4=6 bytes.

   uint32_t 
   YHeader::GetSerializedSize (void) const
   {
     return 6;
   }
   void 
   YHeader::Serialize (Buffer::Iterator start) const
   {
     // The 2 byte-constant
     start.WriteU8 (0xfe);
     start.WriteU8 (0xef);
     // The data.
     start.WriteHtonU32 (m_data);
   }
   uint32_t 
   YHeader::Deserialize (Buffer::Iterator start)
   {
     uint8_t tmp;
     tmp = start.ReadU8 ();
     NS_ASSERT (tmp == 0xfe);
     tmp = start.ReadU8 ();
     NS_ASSERT (tmp == 0xef);
     m_data = start.ReadNtohU32 ();
     return 6; // the number of bytes consumed.
   }

Finally, to make sure that Packet::Print also prints the content of your header, just as it prints the content of the other headers of the system, you need to provide a Print method:

   void 
   YHeader::Print (std::ostream &os) const
   {
     os << "data=" << m_data;
   }

The code will look the same if you want to implement a trailer, that is, a protocol data structure which will be appended to the end of the packet, not its start: you need to make sure that you derive from the ns3::Trailer base class and that you call Packet::AddTrailer and Packet::RemoveTrailer. Another important detail is that you must make sure to rewind the iterator in your Serialize and Deserialize methods writing to or reading from the underlying buffer.