Bug 2064 - UdpSocket::GetMtu() needed
UdpSocket::GetMtu() needed
Status: ASSIGNED
Product: ns-3
Classification: Unclassified
Component: internet
ns-3-dev
All All
: P5 enhancement
Assigned To: Tom Henderson
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2015-02-13 16:21 EST by Tom Henderson
Modified: 2016-04-07 17:28 EDT (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Tom Henderson 2015-02-13 16:21:31 EST
I plan to provide a patch along these lines, if there are no comments.

Socket has GetTxAvailable() that returns the maximum segment uint32_t MAX_IPV4_UDP_DATAGRAM_SIZE = 65507 (which can be fragmented by IP), but what applications could instead really use is the analog of getsockopt(IP MTU) so that they know what is the max Send() size that avoids fragmentation.

Since we have no PMTU discovery, I propose for now.

  if (I am connected to a IPv4 unicast destination address)
    {
      lookup an IPv4 route to destination;
      return the MTU of the device corresponding to the route;
    }
  else if (I am connected to an IPv6 unicast destination)
    {
      lookup an IPv6 route to destination;
      return the MTU of the device corresponding to the route;
    }
  else if (broadcast/multicast)
    {
        return minimum MTU of the devices involved;
    }
  else if (bound to an endpoint but not connected)
    {
       return (ipv4 endpoint? 576 : 1280);
    }
  else
    {
       return 576;
    }
Comment 1 Tommaso Pecorella 2015-02-13 16:29:09 EST
(In reply to Tom Henderson from comment #0)
> Since we have no PMTU discovery,

Wrong, PMTU is alive and kickin' in IPv6. We don't have a GetPmtu tho. Until now there was no need for one, so there's only a setter (SetPmtu).

About the last else, I'd rather return the minimum MTU of the connected devices.

T.
Comment 2 Tom Henderson 2015-02-13 16:31:43 EST
(In reply to Tommaso Pecorella from comment #1)
> (In reply to Tom Henderson from comment #0)
> > Since we have no PMTU discovery,
> 
> Wrong, PMTU is alive and kickin' in IPv6. We don't have a GetPmtu tho. Until
> now there was no need for one, so there's only a setter (SetPmtu).

duly noted.  this should return any discovered MTU, if available.

> 
> About the last else, I'd rather return the minimum MTU of the connected
> devices.
> 
> T.


Can you clarify?  The last else clause was for handling the unconnected/unbound case.
Comment 3 Tommaso Pecorella 2015-02-13 16:45:36 EST
(In reply to Tom Henderson from comment #2)
> (In reply to Tommaso Pecorella from comment #1)
> > About the last else, I'd rather return the minimum MTU of the connected
> > devices.
> 
> Can you clarify?  The last else clause was for handling the
> unconnected/unbound case.

UDP can be used without a Connect (it's connectionless after all). As a consequence, the "unconnected and unbound" case is perfectly ok, and I'd expect also not that uncommon.

576 is too short for IPv6, which may be an issue (IPv6 unbound and unconnected sockets would fail).

However, we can safely assume that the MTU could be the one of one of our interfaces. Since we don't know which will be the outgoing interface, choosing the minimum MTU of the connected interfaces makes sense.

As a side note, the PMTU algorithm starts by setting the tentative MTU to the one of the local interface, and then it reduces it if needed.

As a last note, I guess that the new function is meant to be used by applications. Why not a "GetMtu(Address dst)" then ? The app should know what's the destination, and this would fix the ambiguity.
Comment 4 Tom Henderson 2015-02-13 16:56:08 EST
(In reply to Tommaso Pecorella from comment #3)
> (In reply to Tom Henderson from comment #2)
> > (In reply to Tommaso Pecorella from comment #1)
> > > About the last else, I'd rather return the minimum MTU of the connected
> > > devices.
> > 
> > Can you clarify?  The last else clause was for handling the
> > unconnected/unbound case.
> 
> UDP can be used without a Connect (it's connectionless after all). As a
> consequence, the "unconnected and unbound" case is perfectly ok, and I'd
> expect also not that uncommon.
> 
> 576 is too short for IPv6, which may be an issue (IPv6 unbound and
> unconnected sockets would fail).
> 
> However, we can safely assume that the MTU could be the one of one of our
> interfaces. Since we don't know which will be the outgoing interface,
> choosing the minimum MTU of the connected interfaces makes sense.
> 
> As a side note, the PMTU algorithm starts by setting the tentative MTU to
> the one of the local interface, and then it reduces it if needed.
> 
> As a last note, I guess that the new function is meant to be used by
> applications. Why not a "GetMtu(Address dst)" then ? The app should know
> what's the destination, and this would fix the ambiguity.

I like this last suggestion; it leaves the guesswork out.  If someone needs the more general call, he or she can add it in the future.

If there is no route to dst, then I propose to return the minimum MTU of all possible devices as you suggested.
Comment 5 Tommaso Pecorella 2016-04-07 17:11:36 EDT
A quick update on this enhancement. I checked what Linux is supposed to do, and here's the answer: http://man7.org/linux/man-pages/man7/ip.7.html

the relevant section is:
       IP_MTU (since Linux 2.2)
              Retrieve the current known path MTU of the current socket.
              Returns an integer.

              IP_MTU is valid only for getsockopt(2) and can be employed
              only when the socket has been connected.

and

       IP_MTU_DISCOVER (since Linux 2.2)
              Set or receive the Path MTU Discovery setting for a socket.
...
              When PMTU discovery is enabled, the kernel automatically keeps
              track of the path MTU per destination host.  When it is
              connected to a specific peer with connect(2), the currently
              known path MTU can be retrieved conveniently using the IP_MTU
              socket option (e.g., after an EMSGSIZE error occurred).  The
              path MTU may change over time.  For connectionless sockets
              with many destinations, the new MTU for a given destination
              can also be accessed using the error queue (see IP_RECVERR).
              A new error will be queued for every incoming MTU update.

Practically this means that we need 2 (or more) APIs.
1) GetMtu (): relieves the PMTU for a *connected* socket.
2) GetMtu (destination address): relieves the PMTU for a *non-connected* socket.
3) MtuChanged (source address): *callback* - something changed.

1 and 2 could be collapsed into one (default argument).
3 can work on connected or non-connected mode.

Note that right now we have PMTU for IPv6, so it's easy to add the proposed interface for IPv6. IPv4, in the country, we need to implement RFC 1191. It's not hard, but it's something to do.
Comment 6 Tommaso Pecorella 2016-04-07 17:28:26 EDT
A further comment.

TCP should react in a different way to PMTU probing packet losses. From RFC 1191:

   Modern TCP implementations incorporate "congestion advoidance" and
   "slow-start" algorithms to improve performance [4].  Unlike a
   retransmission caused by a TCP retransmission timeout, a
   retransmission caused by a Datagram Too Big message should not change
   the congestion window.  It should, however, trigger the slow-start
   mechanism (i.e., only one segment should be retransmitted until
   acknowledgements begin to arrive again).


While in IPv4 you have to explicitly set a flag to prevent fragmentation (thus enabling PMTU), PMTU discovery is mandatory in IPv6.

In other words, bug #1751 (TCP should react to MTU changes) is relevant.