Sarajevo, Bosnia and Herzegovina

Socket::SetIpTos in NS-3 ver.3.26

One of the changes between ns-3 ver 3.25 and ver 3.26 is that now it is possible to set TOS value to the address. Yes, you read it right, TOS value to the address. Official Doxygen states following:
https://www.nsnam.org/docs/release/3.26/models/html/sockets-api.html

The native sockets API for ns-3 provides two public methods (of the Socket base class):

void SetIpTos (uint8_t ipTos);
uint8_t GetIpTos (void) const;

to set and get, respectively, the type of service associated with the socket. These methods are equivalent to using the IP_TOS option of BSD sockets. Clearly, setting the type of service only applies to sockets using the IPv4 protocol. However, users typically do not set the type of service associated with a socket through ns3::Socket::SetIpTos() because sockets are normally created by application helpers and users cannot get a pointer to the sockets. Instead, users can create an address of type ns3::InetSocketAddress with the desired type of service value and pass it to the application helpers:

InetSocketAddress destAddress (ipv4Address, udpPort);
destAddress.SetTos (tos);
OnOffHelper onoff ("ns3::UdpSocketFactory", destAddress);

For this to work, the application must eventually call the ns3::Socket::Connect() method to connect to the provided destAddress and the Connect method of the particular socket type must support setting the type of service associated with a socket (by using the ns3::Socket::SetIpTos() method). Currently, the socket types that support setting the type of service in such a way are ns3::UdpSocketImpl and ns3::TcpSocketBase.

The type of service associated with a socket is then used to determine the value of the Type of Service field (renamed as Differentiated Services field by RFC 2474) of the IPv4 header of the packets sent through that socket, as detailed in the next sections.

However, this might cause some issues with your code if you used SetIpTos on socket before Bind or BindToNetDevice. To be precise, this will not work:

//setIPtos to top priority
m_sendSocket->SetIpTos(16);
m_sendSocket->SetIpRecvTos(true);
m_sendSocket->Bind (m_local); 
m_sendSocket->BindToNetDevice(m_sendDevice);

ToS value will be “0”. Because in TcpSocketBase::Bind and TcpSocketBase::Connect TOS value is overwritten to “0” if there is no TOS value set to the address!

TcpSocketBase::Bind (const Address &address)
{
NS_LOG_FUNCTION (this << address);
if (InetSocketAddress::IsMatchingType (address))
{
InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
Ipv4Address ipv4 = transport.GetIpv4 ();
uint16_t port = transport.GetPort ();
SetIpTos (transport.GetTos ());//<<<<<<<<<<
/* Inherit from Socket class: Initiate connection to a remote address:port */
int
TcpSocketBase::Connect (const Address & address)
{
  NS_LOG_FUNCTION (this << address);

  // If haven't do so, Bind() this socket first
  if (InetSocketAddress::IsMatchingType (address) && m_endPoint6 == 0)
    {
      NS_LOG_FUNCTION (this << address << "It is IPv4");

      if (m_endPoint == 0)
        {

          NS_LOG_FUNCTION (this << address << "m_endPoint is empty" << m_endPoint);
          if (Bind () == -1)
            {
              NS_LOG_FUNCTION (this << address << "BIND FAILED");
              NS_ASSERT (m_endPoint == 0);
              return -1; // Bind() failed
            }
          NS_ASSERT (m_endPoint != 0);
        }

        NS_LOG_FUNCTION (this << address << "m_endPoint is NOT empty" << m_endPoint); InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); m_endPoint->SetPeer (transport.GetIpv4 (), transport.GetPort ());
      SetIpTos (transport.GetTos ()); //<<<<<<<<<<

Therefore, the only way to set TOS directly to the socket is to do it after Bind, BindToNetDevice and after Connect:

/**
  * SEND socket settings
  */
  // Create the socket if not already
  if (!m_sendSocket)
      m_sendSocket = Socket::CreateSocket (GetNode (), m_tid);

  m_sendSocket->Bind (m_local);
  m_sendSocket->BindToNetDevice(m_sendDevice);

  //initate TCP-threehand shaking

  if (InetSocketAddress::IsMatchingType (m_peer))
    NS_LOG_FUNCTION (this << m_peer << "IT IS IPV4!!!!!"); m_sendSocket->Connect (m_peer);
  //setIPtos to top priority
  m_sendSocket->SetIpTos(16);
  m_sendSocket->SetIpRecvTos(true);
  //disable receiving any data on this socket
  m_sendSocket->ShutdownRecv ();

So it means that SYN packets cannot be carried with IPv4 which has TOS different from 0!

Although the idea of setting ToS value to address might simplify simulations since the user needs to change only the main script without modifying the deeper code, the problem arises when there are multiple sockets in the application that are using the same IP address (I do not want for all of them to have the same TOS value).

I’m writing this post as a proposal to support both ways of setting TOS to the socket.

——————————-

Update (18.12.2016):
I created a patch for NS3.26 to enable both ways (old by using socket->SetIpTos and the latest by setting ToS via InetSocketAddress) of setting TOS to the socket. Patch is available for download on link: tos_fix.patch

M