Bug 2555

Summary: Inet to Address conversion drops the TOS
Product: ns-3 Reporter: Tommaso Pecorella <tommaso.pecorella>
Component: traffic-controlAssignee: Stefano Avallone <stavallo>
Status: NEEDINFO ---    
Severity: major CC: miralemmehic, ns-bugs
Priority: P5    
Version: ns-3-dev   
Hardware: All   
OS: All   
Attachments: Patch for ToS supporting socket.SetIpTos and InetSocketAddress.SetTos

Description Tommaso Pecorella 2016-11-11 19:40:58 EST
The discussion is here:
https://groups.google.com/forum/#!topic/ns-3-users/SSYjxAnQANM

Basically the problem is that any conversion between an InetSocketAddress to Address will discard the Tos.
This is not safe, and a lot of applications will loose silently the Tos in this way.
Comment 1 Stefano Avallone 2016-11-12 10:34:34 EST
Forgive me, could you please point me to some of such lossy conversions?
Comment 2 Tommaso Pecorella 2016-11-12 19:08:22 EST
(In reply to Stefano Avallone from comment #1)
> Forgive me, could you please point me to some of such lossy conversions?

In examples/traffic-control/traffic-control.cc there is this:

  AddressValue remoteAddress (InetSocketAddress (interfaces.GetAddress (0), port));
  onoff.SetAttribute ("Remote", remoteAddress);
  apps.Add (onoff.Install (nodes.Get (1)));
  apps.Start (Seconds (1.0));
  apps.Stop (Seconds (simulationTime + 0.1));

You can not set the TOS without adding one more parameter to the helper, because even if you add the proper TOS to InetSocketAddress (interfaces.GetAddress (0), port), it will be lost in the conversion to AddressValue (it's a constructor for real).
Comment 3 Stefano Avallone 2016-11-13 10:08:24 EST
To my understanding, Address objects do not involve real conversions. They have a buffer which is simply carried around. What changed with the addition of the ToS field is that this buffer is 7 bytes long instead of 6. If "conversions" were a problem, then you would have issues with the IP address and port as well, since they are not defined in the Address base class.

As a proof, I changed the code in traffic-control.cc to:

  InetSocketAddress rmt (interfaces.GetAddress (0), port);
  rmt.SetTos (0xb8);
  AddressValue remoteAddress (rmt);
  onoff.SetAttribute ("Remote", remoteAddress);
  apps.Add (onoff.Install (nodes.Get (1)));
  apps.Start (Seconds (1.0));
  apps.Stop (Seconds (simulationTime + 0.1));

and used the (updated) patch in codereview 304500043 to show the DSCP of the packets:

*** Flow monitor statistics ***
  Tx Packets:   7682
  Tx Bytes:   11509900
  Offered Load: 10.003 Mbps
  Rx Packets:   7641
  Rx Bytes:   11448400
  Packets Dropped by Queue Disc:   41
  Bytes Dropped by Queue Disc:   61500
  Packets Dropped by NetDevice:   0
  Bytes Dropped by NetDevice:   0
  Throughput: 9.94953 Mbps
  Mean delay:   0.0143646
  Mean jitter:   0.00119161
  DSCP value:   0x2e

which shows that the TOS is correctly set.
Comment 4 Tommaso Pecorella 2016-11-13 10:32:27 EST
You're right. Perhaps we should add an example.

Closing this bug as invalid.
Comment 5 Miralem Mehic 2016-12-17 08:45:49 EST
Hi Guys, 

sorry for late response! 

I'm new in NS3 developing groups and emails, so I cannot find codereview 304500043 which you mentioned. Stefano, can you please attach your testing script or point me a link to your testing script? I cannot get it work with your solution. 

Thanks,
M
Comment 6 Miralem Mehic 2016-12-17 10:26:00 EST
OK, I made it working but I would like to propose additional code to support both ways (old by using socket->SetIpTos and the latest by setting ToS via InetSocketAddress) of setting TOS values. 

Just to add one "if loop" before calling function SetIpTos in TcpSocketBase. This loop is used to check whether ToS is set to the address and add that ToS value if it is set. Otherwise, ToS value which was set by the socket->SetIpTos will remain and it will not be overwritten. 

What do you think?

int
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 ();

      if( transport.GetTos () > 0) {//THIS LINE; Note that ToS is 0 by default
        SetIpTos (transport.GetTos ());
      }


and here


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
    {
      if (m_endPoint == 0)
        {
          if (Bind () == -1)
            {
              NS_ASSERT (m_endPoint == 0);
              return -1; // Bind() failed
            }
          NS_ASSERT (m_endPoint != 0);
        }
      InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
      m_endPoint->SetPeer (transport.GetIpv4 (), transport.GetPort ()); 

      if( transport.GetTos () > 0){ //THIS LINE; Note that ToS is 0 by default
        SetIpTos (transport.GetTos ());
      }
Comment 7 Miralem Mehic 2016-12-18 18:28:33 EST
Created attachment 2711 [details]
Patch for ToS supporting socket.SetIpTos and InetSocketAddress.SetTos

My previous comment is related to TCP but it cannot work for UDP. Therefore, I provide patch for tcp-socket-base.cc and udp-socket-impl.cc in attachment. 

The patch is tested using traffic-control.cc.
Comment 8 Stefano Avallone 2017-01-25 05:40:16 EST
Hi Miralem,

I think you can get the old behavior by calling Socket::SetIpTos after invonking bind and connect. Correct?
Comment 9 Miralem Mehic 2017-01-26 14:44:33 EST
(In reply to Stefano Avallone from comment #8)
> Hi Miralem,
> 
> I think you can get the old behavior by calling Socket::SetIpTos after
> invonking bind and connect. Correct?

Sure, but that will mean that Connect (TCP handshake) packets will be sent without TOS value, right?