This diff implements socket splicing for relayd. Instead of copying data in userland from one TCP socket into another, the kernel is told to move the data himself.
The environment variable RELAY_NOSPLICE works like EVENT_NOKQUEUE from libevent. It can be used to easily turn it on and off for testing. At the moment, I have only implemented plain TCP connections in relayd. HTTP can be done later. If you are using relayd with OpenBSD 4.9 to relay TCP connections, please test this. ok? bluhm Index: usr.sbin/relayd/parse.y =================================================================== RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/relayd/parse.y,v retrieving revision 1.149 diff -u -p -r1.149 parse.y --- usr.sbin/relayd/parse.y 26 Oct 2010 15:04:37 -0000 1.149 +++ usr.sbin/relayd/parse.y 31 Jan 2011 23:34:13 -0000 @@ -796,6 +796,9 @@ proto : relay_proto PROTO STRING { free($3); p->id = ++last_proto_id; p->type = $1; + if (p->type == RELAY_PROTO_TCP && + !getenv("RELAY_NOSPLICE")) + p->flags |= F_SPLICE; p->cache = RELAY_CACHESIZE; p->tcpflags = TCPFLAG_DEFAULT; p->sslflags = SSLFLAG_DEFAULT; @@ -2170,6 +2173,8 @@ parse_config(const char *filename, int o (void)strlcpy(conf->sc_proto_default.sslciphers, SSLCIPHERS_DEFAULT, sizeof(conf->sc_proto_default.sslciphers)); conf->sc_proto_default.type = RELAY_PROTO_TCP; + if (!getenv("RELAY_NOSPLICE")) + conf->sc_proto_default.flags |= F_SPLICE; (void)strlcpy(conf->sc_proto_default.name, "default", sizeof(conf->sc_proto_default.name)); RB_INIT(&conf->sc_proto_default.request_tree); Index: usr.sbin/relayd/relay.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/relayd/relay.c,v retrieving revision 1.128 diff -u -p -r1.128 relay.c --- usr.sbin/relayd/relay.c 20 Dec 2010 12:38:06 -0000 1.128 +++ usr.sbin/relayd/relay.c 31 Jan 2011 23:19:59 -0000 @@ -2328,6 +2328,21 @@ relay_connect(struct rsession *con) return (-1); } + if (rlay->rl_proto->flags & F_SPLICE) { + if (setsockopt(con->se_in.s, SOL_SOCKET, SO_SPLICE, + &con->se_out.s, sizeof(int)) == -1) { + log_debug("relay_connect: session %d: splice forward " + "failed: %s", con->se_id, strerror(errno)); + return (-1); + } + if (setsockopt(con->se_out.s, SOL_SOCKET, SO_SPLICE, + &con->se_in.s, sizeof(int)) == -1) { + log_debug("relay_connect: session %d: splice backward " + "failed: %s", con->se_id, strerror(errno)); + return (-1); + } + } + if (errno == EINPROGRESS) event_again(&con->se_ev, con->se_out.s, EV_WRITE|EV_TIMEOUT, relay_connected, &con->se_tv_start, &env->sc_timeout, con); Index: usr.sbin/relayd/relayd.8 =================================================================== RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/relayd/relayd.8,v retrieving revision 1.23 diff -u -p -r1.23 relayd.8 --- usr.sbin/relayd/relayd.8 24 May 2010 19:44:23 -0000 1.23 +++ usr.sbin/relayd/relayd.8 1 Feb 2011 00:10:22 -0000 @@ -121,6 +121,10 @@ Only check the configuration file for va .It Fl v Produce more verbose output. .El +.Sh ENVIRONMENT +It is possible to disable support for socket splicing by setting +the environment variable +.Ev RELAY_NOSPLICE . .Sh FILES .Bl -tag -width "/var/run/relayd.sockXX" -compact .It /etc/relayd.conf Index: usr.sbin/relayd/relayd.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/relayd/relayd.h,v retrieving revision 1.140 diff -u -p -r1.140 relayd.h --- usr.sbin/relayd/relayd.h 31 Dec 2010 21:22:42 -0000 1.140 +++ usr.sbin/relayd/relayd.h 31 Jan 2011 23:18:49 -0000 @@ -249,6 +249,7 @@ TAILQ_HEAD(addresslist, address); #define F_SSLCLIENT 0x00200000 #define F_NEEDRT 0x00400000 #define F_MATCH 0x00800000 +#define F_SPLICE 0x01000000 enum forwardmode { FWD_NORMAL = 0,