dccp_send: send data in MPS-sized chunks
authorGerrit Renker <grenker@cscs.ch>
Sun, 23 May 2010 05:43:04 +0000 (07:43 +0200)
committerAndre Noll <maan@systemlinux.org>
Mon, 7 Jun 2010 21:24:53 +0000 (23:24 +0200)
As mandated by RFC 4340, 14., DCCP maintains an internal variable called
'Maximum Packet Size', which can be queried via the DCCP_SOCKOPT_GET_CUR_MPS
socket option. This option has been available since 2007-10-04 (v2.6.23)
and is documented in Documentation/networking/dccp.txt.

The Maximum Packet Size takes into account the path MTU, size of headers and
the estimated overhead for DCCP options. The following table shows various
values that were determined experimentally between two hosts:

     +----------+------------+--------------+--------------------+
     | Medium   | IP version | MTU in bytes | Resulting DCCP MPS |
     +----------+------------+--------------+--------------------+
     | Ethernet |    IPv4    |     1500     |     1424 bytes     |
     | Ethernet |    IPv6    |     1500     |     1404 bytes     |
     +----------+------------+--------------+--------------------+
     | WiFi     |    IPv4    |      576     |      500 bytes     |
     | WiFi     |    IPv4    |     1280     |     1204 bytes     |
     | WiFi     |    IPv4    |     1500     |     1424 bytes     |
     | WiFi (a) |    IPv4    |     2048     |     1972 bytes     |
     +----------+------------+--------------+--------------------+
     | WiFi     |    IPv6    |      576     |      see (b)       |
     | WiFi     |    IPv6    |     1280     |     1184 bytes     |
     | WiFi     |    IPv6    |     1500     |     1404 bytes     |
     | WiFi (a) |    IPv6    |     2048     |     1952 bytes     |
     +----------+------------+--------------+--------------------+

Notes:
 (a) WiFi normally uses Ethernet MTU of 1500 bytes, but the medium
     supports a much larger MTU (Fragmentation threshold) of up to
     about 2300 bytes (system used 802.11g).
 (b) 576 byte MTU not tested for IPv6 since IPv6 mandates a minimum
     MTU of 1280 bytes, as per RFC 2460 section 5 (also RFC 5405, 3.2).

The patch implements the dccp init_fec() function based on the DCCP MPS.

dccp_send.c
net.h

index 0657d11..77bee09 100644 (file)
@@ -32,9 +32,6 @@
 #include "server.cmdline.h"
 #include "acl.h"
 
-/** Do not write more than that many bytes at once. */
-#define DCCP_MAX_BYTES_PER_WRITE 1024
-
 static struct sender_status dccp_sender_status, *dss = &dccp_sender_status;
 
 struct dccp_fec_client {
@@ -86,9 +83,26 @@ static void dccp_shutdown_clients(void)
                dccp_shutdown_client(sc);
 }
 
+/** * Obtain current MPS according to RFC 4340, sec. 14. */
+static int dccp_init_fec(struct sender_client *sc)
+{
+       int mps, ret;
+       socklen_t ml = sizeof(mps);
+
+       /* If call fails, return some sensible minimum value */
+       ret = getsockopt(sc->fd, SOL_DCCP, DCCP_SOCKOPT_GET_CUR_MPS, &mps, &ml);
+       if (ret < 0) {
+               PARA_NOTICE_LOG("can not determine MPS: %s\n", strerror(errno));
+               mps = generic_max_transport_msg_size(sc->fd) - DCCP_MAX_HEADER;
+       }
+       PARA_INFO_LOG("current MPS = %d bytes\n", mps);
+       assert(mps > 0);
+       return mps;
+}
+
 static int dccp_send_fec(struct sender_client *sc, char *buf, size_t len)
 {
-       int ret = write_nonblock(sc->fd, buf, len, DCCP_MAX_BYTES_PER_WRITE);
+       int ret = write_nonblock(sc->fd, buf, len, 0);
 
        if (ret < 0)
                dccp_shutdown_client(sc);
@@ -127,8 +141,7 @@ static void dccp_post_select(fd_set *rfds, __a_unused fd_set *wfds)
        sc->private_data = dfc;
        dfc->fcp.slices_per_group       = 4;
        dfc->fcp.data_slices_per_group  = 3;
-       dfc->fcp.max_slice_bytes        = DCCP_MAX_BYTES_PER_WRITE; /* FIXME */
-       dfc->fcp.init_fec               = NULL; /* FIXME */
+       dfc->fcp.init_fec               = dccp_init_fec;
        dfc->fcp.send_fec               = dccp_send_fec;
        dfc->fc = vss_add_fec_client(sc, &dfc->fcp);
 }
diff --git a/net.h b/net.h
index db61031..9da63ba 100644 (file)
--- a/net.h
+++ b/net.h
 #define SOL_DCCP 269 /**< Linux socket level. */
 #endif
 
+#ifndef DCCP_SOCKOPT_GET_CUR_MPS
+#define DCCP_SOCKOPT_GET_CUR_MPS  5 /**< Max packet size, RFC 4340, 14. */
+#endif
+
 #ifndef DCCP_SOCKOPT_AVAILABLE_CCIDS
 #define DCCP_SOCKOPT_AVAILABLE_CCIDS 12 /**< List of supported CCIDs. */
 #endif
@@ -154,6 +158,8 @@ ssize_t send_cred_buffer(int, char*);
 /**
  * Functions and definitions to support \p IPPROTO_DCCP
  */
-/** Hardcoded maximum number of separate CCID modules compiled into a host */
+/** Estimated worst-case length of a DCCP header including options. */
+#define DCCP_MAX_HEADER                128
+/** Hardcoded maximum number of separate CCID modules compiled into a host. */
 #define DCCP_MAX_HOST_CCIDS    20
 extern int dccp_available_ccids(uint8_t **ccid_array);