Socket::SetIpTos in NS-3 ver.3.26

401 views
Skip to first unread message

Miralem Mehic

unread,
Nov 10, 2016, 11:38:03 AM11/10/16
to ns-3-users

One of the changes between ns-3 ver 3.25 and ver 3.26 is that it is possible to set TOS value to the address. 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):

  1. void SetIpTos (uint8_t ipTos);
  2. 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:

  1. InetSocketAddress destAddress (ipv4Address, udpPort);
  2. destAddress.SetTos (tos);
  3. 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, I'm not able to assign TOS value to the socket using the old way from 3.25  m_sendSocket->SetIpTos(16); because TOS is overwritten in TcpSocketBase::Bind, but also in TcpSocketBase::Connect

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 ());
      if (ipv4 == Ipv4Address::GetAny () && port == 0)


/* Inherit from Socket class: Initiate connection to a remote address:port */
int
VirtualTcpSocketBase::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 ());
      m_endPoint6 = 0;

So 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.

M

Tommaso Pecorella

unread,
Nov 10, 2016, 7:13:53 PM11/10/16
to ns-3-users
Hi,

sorry, but I don't understand what the problem is.
Instead of:
  m_sendSocket->Connect (m_peer);
 
//setIPtos to top priority
  m_sendSocket
->SetIpTos(16);

You should use:
  //setIPtos to top priority
  m_peer
.SetTos(16)
  m_sendSocket
->Connect (m_peer);

This will fix the issue of SYN being sent with a different TOS.

Cheers,

T.

Miralem Mehic

unread,
Nov 11, 2016, 2:12:27 PM11/11/16
to ns-3-users
Hi Tommaso,

actually that is not possible:

error: class ns3::Address has no member named SetTos
   m_peer
.SetTos(16);

It is possible to use SetTos only on ns3::InetSocketAddress

void ns3::InetSocketAddress::SetTos     (     uint8_t      tos    )    

and Connect accept only const Address& as parameter:

/* Inherit from Socket class: Initiate connection to a remote address:port */
int
TcpSocketBase::Connect (const Address & address)


I wrote my previous post to propose supporting both ways of setting TOS. The problem arises when there are multiple sockets in the application that use the same address so for each of them it is necessary to check/write/clear ToS value from InetSocketAddress prior using. The current way of setting ToS to ns3::InetSocketAddress does not help too much. For example, how do you set ToS of the socket used in OnOffApplication since OnOffHelper accepts only Address, not InetSocketAddress?

OnOffHelper::OnOffHelper (std::string protocol, Address address)
{
  m_factory
.SetTypeId ("ns3::OnOffApplication");
  m_factory
.Set ("Protocol", StringValue (protocol));
  m_factory
.Set ("Remote", AddressValue (address));
}

so when you use OnOffApplication it is necessary to convert from InetSocketAddress to Address. And gues what, ToS is ignored.

  NS_LOG_INFO
("Create Applications.");
  uint16_t port
= 9;   // Discard port (RFC 863)

 
OnOffHelper onoff ("ns3::UdpSocketFactory",

                     
Address (InetSocketAddress (i3i2.GetAddress (0), port)));
  onoff
.SetConstantRate (DataRate ("448kb/s"));
 
ApplicationContainer apps = onoff.Install (c.Get (0));
  apps
.Start (Seconds (1.0));
  apps
.Stop (Seconds (10.0));


Please find attached "simple-global-routing.cc" from /examples/routing folder where OnOffApplication is used. Please, try to set ToS to some value.

Best,
M
simple-global-routing.cc

Tommaso Pecorella

unread,
Nov 11, 2016, 7:43:21 PM11/11/16
to ns-3-users, Stefano Avallone
Hi,

I appreciate the proposals, but please try to give all the details in the future.

The problem you've found is a design one. Most applications store addresses as the base class (not using pointers). The Address class is smart enough to recognize the kind of address it's storing, even after a "downcast" (it's not really a downcast), BUT you'll loose any additional info of the derived classes.

Since this kind of conversion is made in a lot of places, probably we'll have to think twice to the overall design.

I'd say to move further discussions to ns-devs mailing list. I also opened a bug: https://www.nsnam.org/bugzilla/show_bug.cgi?id=2555


T.

Miralem Mehic

unread,
Nov 12, 2016, 4:30:48 AM11/12/16
to ns-3-users, stav...@gmail.com
ACK & OK

Just to note that issue reported in the topic "TcpSocketBase::BindToNetDevice isssue" is not related to this topic. BindToNotDevice simply does not work with TCP sockets in 3.26.
I just registered on Bugzilla and I would like to contribute in bug hunting/resolving process of NS-3.

Best,
M

Stefano Avallone

unread,
Nov 12, 2016, 10:09:14 AM11/12/16
to Miralem Mehic, ns-3-users
Miralem,

you may want to have a look at the models documentation section about setting socket options:

https://www.nsnam.org/docs/models/html/sockets-api.html?highlight=socket#socket-options

In summary, you can set the ToS for the socket opened by your OnOff application this way:
InetSocketAddress destAddress (ipv4Address, udpPort);
destAddress.SetTos (tos);
OnOffHelper onoff ("ns3::UdpSocketFactory", destAddress);
As Tommaso said, you can pass an InetSocketAddress object to functions requiring an Address object. No information will be lost.

Please let me know if this works and solves your problem.

Bests,
Stefano



Stefano Avallone

unread,
Nov 12, 2016, 10:12:26 AM11/12/16
to Miralem Mehic, ns-3-users
Sorry, I just looked the bug report and the pointer to the google group discussion... 

Stefano Avallone

unread,
Nov 12, 2016, 10:25:47 AM11/12/16
to ns-3-users, mirale...@gmail.com
Can't you declare m_peer as an InetSocketAddress object?

Then, you could do as suggested by Tommaso:
 
  //setIPtos to top priority
  m_peer
.SetTos(16)
  m_sendSocket
->Connect (m_peer); 

You can make multiple connections to the same host:

  //setIPtos to top priority
  m_peer
.SetTos(24)
  m_sendSocket2
->Connect (m_peer); 

Does it solve your problem?

Stefano

Tommaso Pecorella

unread,
Nov 12, 2016, 1:14:33 PM11/12/16
to ns-3-users, mirale...@gmail.com
The problem could be solved with this trick, but it requires a change in the application(s).
Honestly I'd like a more efficient approach, and one that can be merged in ns-3.

Cheers,

T.
Reply all
Reply to author
Forward
0 new messages