RFC: [PATCH] Add TCP congestion control and Diffserv options
David Täht
dave.taht at gmail.com
Mon Nov 28 09:48:57 MST 2011
In the bufferbloat age, anything that can make for a kinder,
gentler bulk transfer protocol seems desirable.
This add support for user and server selectable congestion control
algorithms. As examples:
--congestion-alg=lp # For the tcp-lp algorithm on the command line
Or in a subsection:
[mystuff]
congestion alg = westwood # for a wireless connection
And diffserv support: --diffserv=8 for setting the CS1 bit
This could be improved by being able to specify a list of
congestion algorithms to try, symbolic names for diffserv (CS1),
a better name than 'congestion-alg', and some error checking.
Signed-off-by: Dave Taht <d at taht.net>
---
loadparm.c | 8 ++++++++
options.c | 8 ++++++++
socket.c | 38 ++++++++++++++++++++++++++++++++++++++
3 files changed, 54 insertions(+), 0 deletions(-)
diff --git a/loadparm.c b/loadparm.c
index 965b771..51b1b06 100644
--- a/loadparm.c
+++ b/loadparm.c
@@ -109,6 +109,7 @@ typedef struct {
char *auth_users;
char *charset;
char *comment;
+ char *congestion_alg;
char *dont_compress;
char *exclude;
char *exclude_from;
@@ -138,6 +139,7 @@ typedef struct {
int max_verbosity;
int syslog_facility;
int timeout;
+ int diffserv;
BOOL fake_super;
BOOL forward_lookup;
@@ -185,6 +187,7 @@ static const all_vars Defaults = {
/* auth_users; */ NULL,
/* charset; */ NULL,
/* comment; */ NULL,
+ /* congestion_alg; */ NULL,
/* dont_compress; */ DEFAULT_DONT_COMPRESS,
/* exclude; */ NULL,
/* exclude_from; */ NULL,
@@ -212,6 +215,7 @@ static const all_vars Defaults = {
/* max_verbosity; */ 1,
/* syslog_facility; */ LOG_DAEMON,
/* timeout; */ 0,
+ /* diffserv; */ 8,
/* fake_super; */ False,
/* forward_lookup; */ True,
@@ -322,6 +326,8 @@ static struct parm_struct parm_table[] =
{"auth users", P_STRING, P_LOCAL, &Vars.l.auth_users, NULL,0},
{"charset", P_STRING, P_LOCAL, &Vars.l.charset, NULL,0},
{"comment", P_STRING, P_LOCAL, &Vars.l.comment, NULL,0},
+ {"congestion alg", P_STRING, P_LOCAL, &Vars.l.congestion_alg, NULL,0},
+ {"diffserv", P_INTEGER, P_LOCAL, &Vars.l.diffserv, NULL,0},
{"dont compress", P_STRING, P_LOCAL, &Vars.l.dont_compress, NULL,0},
{"exclude from", P_STRING, P_LOCAL, &Vars.l.exclude_from, NULL,0},
{"exclude", P_STRING, P_LOCAL, &Vars.l.exclude, NULL,0},
@@ -454,6 +460,7 @@ FN_GLOBAL_INTEGER(lp_rsync_port, &Vars.g.rsync_port)
FN_LOCAL_STRING(lp_auth_users, auth_users)
FN_LOCAL_STRING(lp_charset, charset)
FN_LOCAL_STRING(lp_comment, comment)
+FN_LOCAL_STRING(lp_congestion_alg, congestion_alg)
FN_LOCAL_STRING(lp_dont_compress, dont_compress)
FN_LOCAL_STRING(lp_exclude, exclude)
FN_LOCAL_STRING(lp_exclude_from, exclude_from)
@@ -481,6 +488,7 @@ FN_LOCAL_INTEGER(lp_max_connections, max_connections)
FN_LOCAL_INTEGER(lp_max_verbosity, max_verbosity)
FN_LOCAL_INTEGER(lp_syslog_facility, syslog_facility)
FN_LOCAL_INTEGER(lp_timeout, timeout)
+FN_LOCAL_INTEGER(lp_diffserv, diffserv)
FN_LOCAL_BOOL(lp_fake_super, fake_super)
FN_LOCAL_BOOL(lp_forward_lookup, forward_lookup)
diff --git a/options.c b/options.c
index 9e95c86..6085444 100644
--- a/options.c
+++ b/options.c
@@ -69,6 +69,8 @@ int delete_during = 0;
int delete_before = 0;
int delete_after = 0;
int delete_excluded = 0;
+int diffserv = 8;
+char *congestion_alg = NULL;
int remove_source_files = 0;
int one_file_system = 0;
int protocol_version = PROTOCOL_VERSION;
@@ -776,6 +778,8 @@ void usage(enum logcode F)
rprintf(F," --address=ADDRESS bind address for outgoing socket to daemon\n");
rprintf(F," --port=PORT specify double-colon alternate port number\n");
rprintf(F," --sockopts=OPTIONS specify custom TCP options\n");
+ rprintf(F," --diffserv=[0-63] specify diffserv setting \n");
+ rprintf(F," --congestion-alg=STRING choose a congestion algo\n");
rprintf(F," --blocking-io use blocking I/O for the remote shell\n");
rprintf(F," --stats give some file-transfer stats\n");
rprintf(F," -8, --8-bit-output leave high-bit chars unescaped in output\n");
@@ -1027,6 +1031,8 @@ static struct poptOption long_options[] = {
{"no-blocking-io", 0, POPT_ARG_VAL, &blocking_io, 0, 0, 0 },
{"remote-option", 'M', POPT_ARG_STRING, 0, 'M', 0, 0 },
{"protocol", 0, POPT_ARG_INT, &protocol_version, 0, 0, 0 },
+ {"congestion-alg", 0, POPT_ARG_STRING, &congestion_alg, 0, 0, 0 },
+ {"diffserv", 0, POPT_ARG_INT, &diffserv, 0, 0, 0 },
{"checksum-seed", 0, POPT_ARG_INT, &checksum_seed, 0, 0, 0 },
{"server", 0, POPT_ARG_NONE, 0, OPT_SERVER, 0, 0 },
{"sender", 0, POPT_ARG_NONE, 0, OPT_SENDER, 0, 0 },
@@ -1054,6 +1060,8 @@ static void daemon_usage(enum logcode F)
rprintf(F," --log-file=FILE override the \"log file\" setting\n");
rprintf(F," --log-file-format=FMT override the \"log format\" setting\n");
rprintf(F," --sockopts=OPTIONS specify custom TCP options\n");
+ rprintf(F," --diffserv=[0-63] specify diffserv setting \n");
+ rprintf(F," --congestion-alg=STRING choose a congestion algo\n");
rprintf(F," -v, --verbose increase verbosity\n");
rprintf(F," -4, --ipv4 prefer IPv4\n");
rprintf(F," -6, --ipv6 prefer IPv6\n");
diff --git a/socket.c b/socket.c
index 84f9b0c..4ee901e 100644
--- a/socket.c
+++ b/socket.c
@@ -38,6 +38,8 @@ extern char *bind_address;
extern char *sockopts;
extern int default_af_hint;
extern int connect_timeout;
+extern int diffserv;
+extern char *congestion_alg;
#ifdef HAVE_SIGACTION
static struct sigaction sigact;
@@ -166,6 +168,40 @@ static RETSIGTYPE contimeout_handler(UNUSED(int val))
connect_timeout = -1;
}
+/* Set special socket options
+ *
+ * Diffserv is a value in the range of 0-63, and needs to be shifted left
+ * 2 places AND treated differently for ipv4 and ipv6.
+ * Setting TCP congestion control is rather Linux specific (at the moment)
+ * and sends a varying length string to setsockopt rather than an integer
+ * or character.
+*/
+
+void set_special_sockopts(int s)
+{
+#if defined(TCP_CONGESTION)
+ if(congestion_alg) {
+ if(setsockopt(s, SOL_TCP, TCP_CONGESTION, congestion_alg,
+ strlen(congestion_alg)) == -1)
+ rprintf(FINFO, "Couldn't set %s congestion algorithm\n",
+ congestion_alg);
+ }
+#endif
+
+/* setting the diffserv/tos bits is different on ipv6 and
+ * ipv4, so we just hammer down on both and ignore the result
+ * And ipv6 demands an int for v. I didn't write the spec.
+ */
+ if(diffserv) {
+ int v = (diffserv & 63) <<2;
+ setsockopt(s,IPPROTO_IP, IP_TOS, &v, sizeof(v));
+
+#if defined(IPV6_TCLASS)
+ setsockopt(s,IPPROTO_IPV6, IPV6_TCLASS, &v, sizeof(v));
+#endif
+ }
+}
+
/* Open a socket to a tcp remote host with the specified port.
*
* Based on code from Warren. Proxy support by Stephen Rothwell.
@@ -275,6 +311,7 @@ int open_socket_out(char *host, int port, const char *bind_addr,
alarm(connect_timeout);
}
+ set_special_sockopts(s);
set_socket_options(s, sockopts);
while (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
if (connect_timeout < 0)
@@ -449,6 +486,7 @@ static int *open_socket_in(int type, int port, const char *bind_addr,
continue;
}
+ set_special_sockopts(s);
setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
(char *)&one, sizeof one);
if (sockopts)
--
1.7.5.4
--
Dave Täht
More information about the rsync
mailing list