Difference between revisions of "HOWTO create a new type of protocol header or trailer"

From Nsnam
Jump to: navigation, search
(HOWTO create a new type of protocol header or trailer)
 
Line 17: Line 17:
 
       virtual uint32_t Deserialize (Buffer::Iterator start);
 
       virtual uint32_t Deserialize (Buffer::Iterator start);
 
       virtual void Print (std::ostream &os) const;
 
       virtual void Print (std::ostream &os) const;
 
 
       // allow protocol-specific access to the header data.
 
       // allow protocol-specific access to the header data.
 
       void SetData (uint32_t data);
 
       void SetData (uint32_t data);
Line 24: Line 23:
 
       uint32_t m_data;
 
       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.

Revision as of 13:29, 22 May 2009

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 make and use a new application

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.