diff --git a/src/internet/model/tcp-option-sack-permitted.cc b/src/internet/model/tcp-option-sack-permitted.cc new file mode 100644 index 000000000..65e9d65f6 --- /dev/null +++ b/src/internet/model/tcp-option-sack-permitted.cc @@ -0,0 +1,107 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2011 Adrian Sai-wah Tam + * + * 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 + * + * Original Author: Adrian Sai-wah Tam + * Documentation, test cases: Truc Anh N. Nguyen + * ResiliNets Research Group http://wiki.ittc.ku.edu/resilinets + * The University of Kansas + * James P.G. Sterbenz , director + */ + +#include "tcp-option-sack-permitted.h" +#include "ns3/log.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("TcpOptionSackPermitted"); + +NS_OBJECT_ENSURE_REGISTERED (TcpOptionSackPermitted); + +TcpOptionSackPermitted::TcpOptionSackPermitted () + : TcpOption () +{ +} + +TcpOptionSackPermitted::~TcpOptionSackPermitted () +{ +} + +TypeId +TcpOptionSackPermitted::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::TcpOptionSackPermitted") + .SetParent () + .SetGroupName ("Internet") + .AddConstructor () + ; + return tid; +} + +TypeId +TcpOptionSackPermitted::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +void +TcpOptionSackPermitted::Print (std::ostream &os) const +{ + os << "[sack_perm]"; +} + +uint32_t +TcpOptionSackPermitted::GetSerializedSize (void) const +{ + return 2; +} + +void +TcpOptionSackPermitted::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + i.WriteU8 (GetKind ()); // Kind + i.WriteU8 (2); // Length +} + +uint32_t +TcpOptionSackPermitted::Deserialize (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + + uint8_t readKind = i.ReadU8 (); + if (readKind != GetKind ()) + { + NS_LOG_WARN ("Malformed Sack-Permitted option"); + return 0; + } + + uint8_t size = i.ReadU8 (); + if (size != 2) + { + NS_LOG_WARN ("Malformed Sack-Permitted option"); + return 0; + } + return GetSerializedSize (); +} + +uint8_t +TcpOptionSackPermitted::GetKind (void) const +{ + return TcpOption::SACKPERMITTED; +} + +} // namespace ns3 diff --git a/src/internet/model/tcp-option-sack-permitted.h b/src/internet/model/tcp-option-sack-permitted.h new file mode 100644 index 000000000..54c5e63de --- /dev/null +++ b/src/internet/model/tcp-option-sack-permitted.h @@ -0,0 +1,65 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2011 Adrian Sai-wah Tam + * Copyright (c) 2015 ResiliNets, ITTC, University of Kansas + * + * 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 + * + * Original Author: Adrian Sai-wah Tam + * Documentation, test cases: Truc Anh N. Nguyen + * ResiliNets Research Group http://wiki.ittc.ku.edu/resilinets + * The University of Kansas + * James P.G. Sterbenz , director + */ + +#ifndef TCP_OPTION_SACK_PERMITTED_H +#define TCP_OPTION_SACK_PERMITTED_H + +#include "ns3/tcp-option.h" + +namespace ns3 { + +/** + * \brief Defines the TCP option of kind 4 (selective acknowledgment permitted + * option) as in \RFC{2018} + * + * TCP Sack-Permitted Option is 2-byte in length and sent in a SYN segment by a + * TCP host that can recognize and process SACK option during the lifetime of a + * connection. + */ + +class TcpOptionSackPermitted : public TcpOption +{ +public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + + TcpOptionSackPermitted (); + virtual ~TcpOptionSackPermitted (); + + virtual void Print (std::ostream &os) const; + virtual void Serialize (Buffer::Iterator start) const; + virtual uint32_t Deserialize (Buffer::Iterator start); + + virtual uint8_t GetKind (void) const; + virtual uint32_t GetSerializedSize (void) const; +}; + +} // namespace ns3 + +#endif /* TCP_OPTION_SACK_PERMITTED */ diff --git a/src/internet/model/tcp-option-sack.cc b/src/internet/model/tcp-option-sack.cc new file mode 100644 index 000000000..0680fe9bf --- /dev/null +++ b/src/internet/model/tcp-option-sack.cc @@ -0,0 +1,159 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2011 Adrian Sai-wah Tam + * Copyright (c) 2015 ResiliNets, ITTC, University of Kansas + * + * 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 + * + * Original Author: Adrian Sai-wah Tam + * Documentation, test cases: Truc Anh N. Nguyen + * ResiliNets Research Group http://wiki.ittc.ku.edu/resilinets + * The University of Kansas + * James P.G. Sterbenz , director + */ + +#include "tcp-option-sack.h" +#include "ns3/log.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("TcpOptionSack"); + +NS_OBJECT_ENSURE_REGISTERED (TcpOptionSack); + +TcpOptionSack::TcpOptionSack () + : TcpOption () +{ +} + +TcpOptionSack::~TcpOptionSack () +{ +} + +TypeId +TcpOptionSack::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::TcpOptionSack") + .SetParent () + .SetGroupName ("Internet") + .AddConstructor () + ; + return tid; +} + +TypeId +TcpOptionSack::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +void +TcpOptionSack::Print (std::ostream &os) const +{ + os << "blocks: " << GetNumSackBlocks () << ","; + for (SackList::const_iterator it = m_sackList.begin (); it != m_sackList.end (); ++it) + { + os << "[" << it->first << "," << it->second << "]"; + } +} + +uint32_t +TcpOptionSack::GetSerializedSize (void) const +{ + NS_LOG_FUNCTION (this); + NS_LOG_LOGIC ("Serialized size: " << 2 + GetNumSackBlocks () * 8); + return 2 + GetNumSackBlocks () * 8; +} + +void +TcpOptionSack::Serialize (Buffer::Iterator start) const +{ + NS_LOG_FUNCTION (this); + Buffer::Iterator i = start; + i.WriteU8 (GetKind ()); // Kind + uint8_t length = GetNumSackBlocks () * 8 + 2; + i.WriteU8 (length); // Length + + for (SackList::const_iterator it = m_sackList.begin (); it != m_sackList.end (); ++it) + { + SequenceNumber32 leftEdge = it->first; + SequenceNumber32 rightEdge = it->second; + i.WriteHtonU32 (leftEdge.GetValue ()); // Left edge of the block + i.WriteHtonU32 (rightEdge.GetValue ()); // Right edge of the block + } +} + +uint32_t +TcpOptionSack::Deserialize (Buffer::Iterator start) +{ + NS_LOG_FUNCTION (this); + Buffer::Iterator i = start; + uint8_t readKind = i.ReadU8 (); + if (readKind != GetKind ()) + { + NS_LOG_WARN ("Malformed SACK option, wrong type"); + return 0; + } + + uint8_t size = i.ReadU8 (); + NS_LOG_LOGIC ("Size: " << (uint32_t)size); + m_sackList.empty (); + uint8_t sackCount = (size - 2) / 8; + while (sackCount) + { + SequenceNumber32 leftEdge = SequenceNumber32 (i.ReadNtohU32 ()); + SequenceNumber32 rightEdge = SequenceNumber32 (i.ReadNtohU32 ()); + SackBlock s (leftEdge, rightEdge); + AddSackBlock (s); + sackCount--; + } + + return GetSerializedSize (); +} + +uint8_t +TcpOptionSack::GetKind (void) const +{ + return TcpOption::SACK; +} + +void +TcpOptionSack::AddSackBlock (SackBlock s) +{ + NS_LOG_FUNCTION (this); + m_sackList.push_back (s); +} + +uint32_t +TcpOptionSack::GetNumSackBlocks (void) const +{ + NS_LOG_FUNCTION (this); + NS_LOG_LOGIC ("Number of SACK blocks appended: " << m_sackList.size ()); + return m_sackList.size (); +} + +void +TcpOptionSack::ClearSackList (void) +{ + m_sackList.clear (); +} + +TcpOptionSack::SackList +TcpOptionSack::GetSackList (void) const +{ + NS_LOG_FUNCTION (this); + return m_sackList; +} + +} // namespace ns3 diff --git a/src/internet/model/tcp-option-sack.h b/src/internet/model/tcp-option-sack.h new file mode 100644 index 000000000..d33eb6eca --- /dev/null +++ b/src/internet/model/tcp-option-sack.h @@ -0,0 +1,101 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2011 Adrian Sai-wah Tam + * Copyright (c) 2015 ResiliNets, ITTC, University of Kansas + * + * 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 + * + * Original Author: Adrian Sai-wah Tam + * Documentation, test cases: Truc Anh N. Nguyen + * ResiliNets Research Group http://wiki.ittc.ku.edu/resilinets + * The University of Kansas + * James P.G. Sterbenz , director + */ + +#ifndef TCP_OPTION_SACK_H +#define TCP_OPTION_SACK_H + +#include "ns3/tcp-option.h" +#include "ns3/sequence-number.h" + +namespace ns3 { + +/** + * \brief Defines the TCP option of kind 5 (selective acknowledgment option) as + * in \RFC{2018} + * + * TCP SACK Option is used by a receiver to report non-contiguous blocks of data + * that have been received and queued in the receiving buffer. Using the + * information conveyed in SACK option sender retransmits only the segments that + * have actually been lost, allowing the recovery of multiple packet losses per + * sending window. + * + * Each SACK block is defined by two 32-bit unsigned integers specifying the + * left and the right edge of the block. It means that with the 40-byte TCP + * option limitation in addition to the presence of TCP Timestamp Option, the + * maximum number of SACK blocks that can be appended to each segment is 3. + */ +class TcpOptionSack : public TcpOption +{ +public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + + typedef std::pair SackBlock; //!< SACK block definition + typedef std::list SackList; //!< SACK list definition + + TcpOptionSack (); + virtual ~TcpOptionSack (); + + virtual void Print (std::ostream &os) const; + virtual void Serialize (Buffer::Iterator start) const; + virtual uint32_t Deserialize (Buffer::Iterator start); + + virtual uint8_t GetKind (void) const; + virtual uint32_t GetSerializedSize (void) const; + + /** + * \brief Add a SACK block + * \param s the SACK block to be added + */ + void AddSackBlock (SackBlock s); + + /** + * \brief Count the total number of SACK blocks + * \return the total number of SACK blocks + */ + uint32_t GetNumSackBlocks (void) const; + + /** + * \brief Clear the SACK list + */ + void ClearSackList (void); + + /** + * \brief Get the SACK list + * \return the SACK list + */ + SackList GetSackList (void) const; + +protected: + SackList m_sackList; //!< the list of SACK blocks +}; + +} // namespace ns3 + +#endif /* TCP_OPTION_SACK */ diff --git a/src/internet/model/tcp-option.cc b/src/internet/model/tcp-option.cc index d668f197e..cc1939436 100644 --- a/src/internet/model/tcp-option.cc +++ b/src/internet/model/tcp-option.cc @@ -22,6 +22,8 @@ #include "tcp-option-rfc793.h" #include "tcp-option-winscale.h" #include "tcp-option-ts.h" +#include "tcp-option-sack-permitted.h" +#include "tcp-option-sack.h" #include "ns3/type-id.h" #include "ns3/log.h" @@ -71,11 +73,13 @@ TcpOption::CreateOption (uint8_t kind) static ObjectFactory objectFactory; static kindToTid toTid[] = { - { TcpOption::END, TcpOptionEnd::GetTypeId () }, - { TcpOption::MSS, TcpOptionMSS::GetTypeId () }, - { TcpOption::NOP, TcpOptionNOP::GetTypeId () }, - { TcpOption::TS, TcpOptionTS::GetTypeId () }, - { TcpOption::WINSCALE, TcpOptionWinScale::GetTypeId () }, + { TcpOption::END, TcpOptionEnd::GetTypeId () }, + { TcpOption::MSS, TcpOptionMSS::GetTypeId () }, + { TcpOption::NOP, TcpOptionNOP::GetTypeId () }, + { TcpOption::TS, TcpOptionTS::GetTypeId () }, + { TcpOption::WINSCALE, TcpOptionWinScale::GetTypeId () }, + { TcpOption::SACKPERMITTED, TcpOptionSackPermitted::GetTypeId () }, + { TcpOption::SACK, TcpOptionSack::GetTypeId () }, { TcpOption::UNKNOWN, TcpOptionUnknown::GetTypeId () } }; @@ -100,8 +104,10 @@ TcpOption::IsKindKnown (uint8_t kind) case NOP: case MSS: case WINSCALE: + case SACKPERMITTED: + case SACK: case TS: - // Do not add UNKNOWN here + // Do not add UNKNOWN here return true; } @@ -161,7 +167,7 @@ TcpOptionUnknown::Serialize (Buffer::Iterator i) const i.WriteU8 (GetKind ()); i.WriteU8 (GetSerializedSize ()); - i.Write (m_content, m_size-2); + i.Write (m_content, m_size - 2); } uint32_t @@ -179,7 +185,7 @@ TcpOptionUnknown::Deserialize (Buffer::Iterator start) return 0; } - i.Read (m_content, m_size-2); + i.Read (m_content, m_size - 2); return m_size; } diff --git a/src/internet/model/tcp-option.h b/src/internet/model/tcp-option.h index 79d95f8d3..36f5a9a82 100644 --- a/src/internet/model/tcp-option.h +++ b/src/internet/model/tcp-option.h @@ -54,12 +54,14 @@ public: { // Remember to extend IsKindKnown() with new value, when adding values here // - END = 0, //!< END - NOP = 1, //!< NOP - MSS = 2, //!< MSS - WINSCALE = 3, //!< WINSCALE - TS = 8, //!< TS - UNKNOWN = 255 //!< not a standardized value; for unknown recv'd options + END = 0, //!< END + NOP = 1, //!< NOP + MSS = 2, //!< MSS + WINSCALE = 3, //!< WINSCALE + SACKPERMITTED = 4, //!< SACKPERMITTED + SACK = 5, //!< SACK + TS = 8, //!< TS + UNKNOWN = 255 //!< not a standardized value; for unknown recv'd options }; /** diff --git a/src/internet/wscript b/src/internet/wscript index 613b054e1..4b0ed010e 100644 --- a/src/internet/wscript +++ b/src/internet/wscript @@ -162,6 +162,8 @@ def build(bld): 'model/tcp-option-rfc793.cc', 'model/tcp-option-winscale.cc', 'model/tcp-option-ts.cc', + 'model/tcp-option-sack-permitted.cc', + 'model/tcp-option-sack.cc', 'model/ipv4-packet-info-tag.cc', 'model/ipv6-packet-info-tag.cc', 'model/ipv4-interface-address.cc', @@ -290,6 +292,8 @@ def build(bld): 'model/tcp-option.h', 'model/tcp-option-winscale.h', 'model/tcp-option-ts.h', + 'model/tcp-option-sack-permitted.h', + 'model/tcp-option-sack.h', 'model/tcp-option-rfc793.h', 'model/icmpv4.h', 'model/icmpv6-header.h',