Dear ns-3 developers,
We are a group of students currently working on implementation of rLEDBAT in ns-3. We encountered a design question during the implementation.
In rLEDBAT, congestion control is enforced at the receiver by controlling the advertised receive window. The receiver computes a delay-based window using the LEDBAT / LEDBAT++ algorithm and overwrites the advertised receive window accordingly. The sender, independent of its congestion control algorithm (e.g., CUBIC, NewReno), is limited by:
min(cwnd_sender, rwnd_rledbat)As a result, the effective sending behavior follows LEDBAT / LEDBAT++ dynamics while the sender-side congestion control remains unchanged.
My current approach is to implement this by inheriting from TcpSocketBase (as TcpRLedbat) and overriding AdvertisedWindowSize() to apply the rLEDBAT logic. An inheritance diagram is attached for reference.
While working on this, I noticed that TcpL4Protocol always instantiates TcpSocketBase directly in TcpL4Protocol::CreateSocket(), which makes it difficult to substitute a custom TCP socket implementation. RTT estimation, congestion control, and recovery are instantiated using ObjectFactory and configurable via TypeId attributes, but the TCP socket class itself is not configurable in the same way.
I am considering adding a TypeId attribute (such as SocketBaseType) to TcpL4Protocol and instantiating the TCP socket via ObjectFactory, using TcpSocketBase as the default. This would preserve existing behavior unless explicitly configured.
Before proceeding, I wanted to ask the community whether this approach is acceptable, or if there is a preferred alternative for supporting custom TCP socket implementations.
Any suggestions would be appreciated.
Best regards,
Jayesh Akot
Hello Jayesh, responses inline below
Dear ns-3 developers,
We are a group of students currently working on implementation of rLEDBAT in ns-3. We encountered a design question during the implementation.
In rLEDBAT, congestion control is enforced at the receiver by controlling the advertised receive window. The receiver computes a delay-based window using the LEDBAT / LEDBAT++ algorithm and overwrites the advertised receive window accordingly. The sender, independent of its congestion control algorithm (e.g., CUBIC, NewReno), is limited by:
min(cwnd_sender, rwnd_rledbat)As a result, the effective sending behavior follows LEDBAT / LEDBAT++ dynamics while the sender-side congestion control remains unchanged.
My current approach is to implement this by inheriting from TcpSocketBase (as TcpRLedbat) and overriding AdvertisedWindowSize() to apply the rLEDBAT logic. An inheritance diagram is attached for reference.
This would work; an alternative would be to define a new ns3::Callback and hook it into the AdvertisedWindowSize() near the end of the method; something like this:
--- a/src/internet/model/tcp-socket-base.cc
+++ b/src/internet/model/tcp-socket-base.cc
@@ -3696,6 +3696,10 @@ TcpSocketBase::AdvertisedWindowSize(bool
scale) const
NS_LOG_WARN("Adv window size truncated to "
<< m_maxWinSize << "; possibly to
avoid overflow of the 16-bit integer");
}
+ if (!m_advWindowOverride.IsNull())
+ {
+ w = m_advWindowOverride(...);
+ }
NS_LOG_LOGIC("Returning AdvertisedWindowSize of " <<
static_cast<uint16_t>(w));
return static_cast<uint16_t>(w);
}
Then have your rLedbat object provide a callback function when it starts up.
While working on this, I noticed that TcpL4Protocol always instantiates TcpSocketBase directly in TcpL4Protocol::CreateSocket(), which makes it difficult to substitute a custom TCP socket implementation. RTT estimation, congestion control, and recovery are instantiated using ObjectFactory and configurable via TypeId attributes, but the TCP socket class itself is not configurable in the same way.
I am considering adding a TypeId attribute (such as SocketBaseType) to TcpL4Protocol and instantiating the TCP socket via ObjectFactory, using TcpSocketBase as the default. This would preserve existing behavior unless explicitly configured.
Before proceeding, I wanted to ask the community whether this approach is acceptable, or if there is a preferred alternative for supporting custom TCP socket implementations.
This is a good observation. The original intent of the design (20 years ago) was to support multiple implementations and use factories and polymorphism, but the alternative implementations never proliferated; we had one (the network simulation cradle) a while back, but it was eventually removed because it could no longer be supported, and some things ended up being bypassed, it seems, to hardwire the existing TcpSocketBase. You can see some vestiges of the original design intent (a TcpSocket base class but only one TcpSocket concrete class, a TcpSocketFactory base class but only one concrete subclass, etc.), and now you are finding that you can't easily make a different concrete class.
I don't know, offhand, how much work it would be to fix this. However, if you follow the suggestion above and add a callback (that perhaps only pertains to rLedbat, for now), does this solve the problem for you and you no longer need to worry about a custom TcpSocket implementation? Or are you still interested in the latter?
- Tom
Any suggestions would be appreciated.
Best regards,
Jayesh Akot
--
You received this message because you are subscribed to the Google Groups "ns-developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ns-developer...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/ns-developers/9c2698cf-d6d9-491d-83c2-bbf27b81ad90n%40googlegroups.com.
Hello Tom,
Thank you for the suggestion. We will explore the callback-based approach you described and follow up once we have evaluated whether it fully meets our requirements.
In parallel, we also implemented the custom socket–based approach to better understand the feasibility and scope of changes required. The implementation builds successfully, and we created a small example program that runs correctly and produces the expected behavior. With this approach, we are able to instantiate a custom TCP socket (in our case, an rLEDBAT socket) and selectively enable it for specific nodes in the scenario, while leaving other nodes unaffected.
Our rLEDBAT implementation inherits from TcpSocketBase and overrides two functions: ReceivedData(), to access TCP header information from received packets for OWD/RTT-related calculations used by the rLEDBAT controller, and AdvertisedWindowSize(), to advertise the receive window computed by the rLEDBAT algorithm.
We have attached a diff of the changes made to TcpL4Protocol for reference.
Our intent with this approach was to support rLEDBAT while also enabling a more general mechanism for custom TCP socket instantiation, without impacting existing simulations.
We would appreciate your feedback on whether these changes to TcpL4Protocol are sufficient and consistent with ns-3 design practices, or if there are aspects we should reconsider.
Thank you again for your time and guidance.
Best regards,
Jayesh Akot
Jayesh,
Your patch seems reasonable and would preserve backward compatibility. I created issue #1309 to track it, in case you or others want to work on this further.
https://gitlab.com/nsnam/ns-3-dev/-/issues/1309
- Tom
To view this discussion visit https://groups.google.com/d/msgid/ns-developers/4920b6fa-545a-4b2a-8a0e-c496c2c8c52en%40googlegroups.com.
Hello Tom,
Thank you for reviewing the patch and for creating the issue to track it. We appreciate the feedback.
We will continue working on this and will follow up on the issue as we make further progress.
Best regards,
Jayesh