Hi, the following diff adds support for the following scheduling algorithms:
relays + rdrs: - source-hash - random rdrs: - least-states redirect foobar { listen on 198.51.100.24 port 80 forward to <servers> check tcp mode least-states } relay foobar { listen on 198.51.100.25 port 80 forward to <servers> check tcp mode random } Note that relayd does not support weights associated with addresses yet. This will be added later, in a separate diff. Tests? OK? Reyk Index: parse.y =================================================================== RCS file: /cvs/src/usr.sbin/relayd/parse.y,v retrieving revision 1.167 diff -u -p -r1.167 parse.y --- parse.y 4 Oct 2012 20:53:30 -0000 1.167 +++ parse.y 15 Oct 2012 11:42:33 -0000 @@ -30,6 +30,7 @@ #include <sys/stat.h> #include <sys/queue.h> #include <sys/ioctl.h> +#include <sys/hash.h> #include <net/if.h> #include <net/pfvar.h> @@ -157,6 +158,7 @@ typedef struct { %token RETURN ROUNDROBIN ROUTE SACK SCRIPT SEND SESSION SOCKET SPLICE %token SSL STICKYADDR STYLE TABLE TAG TCP TIMEOUT TO ROUTER RTLABEL %token TRANSPARENT TRAP UPDATES URL VIRTUAL WITH TTL RTABLE MATCH +%token RANDOM LEASTSTATES SRCHASH %token <v.string> STRING %token <v.number> NUMBER %type <v.string> hostname interface table @@ -484,9 +486,15 @@ rdroptsl : forwardmode TO tablespec inte if (rdr->table) { rdr->backup = $3; rdr->conf.backup_id = $3->conf.id; + if (dstmode != rdr->conf.mode) { + yyerror("backup table for %s with " + "different mode", rdr->conf.name); + YYERROR; + } } else { rdr->table = $3; rdr->conf.table_id = $3->conf.id; + rdr->conf.mode = dstmode; } $3->conf.fwdmode = $1; $3->conf.rdrid = rdr->conf.id; @@ -682,6 +690,16 @@ tableopts : CHECK tablecheck } /* FALLTHROUGH */ case RELAY_DSTMODE_ROUNDROBIN: + case RELAY_DSTMODE_SRCHASH: + case RELAY_DSTMODE_RANDOM: + dstmode = $2; + break; + case RELAY_DSTMODE_LEASTSTATES: + if (rdr == NULL) { + yyerror("mode not supported " + "for relays"); + YYERROR; + } dstmode = $2; break; } @@ -1435,6 +1453,9 @@ dstmode : /* empty */ { $$ = RELAY_DST | LOADBALANCE { $$ = RELAY_DSTMODE_LOADBALANCE; } | ROUNDROBIN { $$ = RELAY_DSTMODE_ROUNDROBIN; } | HASH { $$ = RELAY_DSTMODE_HASH; } + | LEASTSTATES { $$ = RELAY_DSTMODE_LEASTSTATES; } + | SRCHASH { $$ = RELAY_DSTMODE_SRCHASH; } + | RANDOM { $$ = RELAY_DSTMODE_RANDOM; } ; router : ROUTER STRING { @@ -1794,6 +1815,7 @@ lookup(char *s) { "interval", INTERVAL }, { "ip", IP }, { "label", LABEL }, + { "least-states", LEASTSTATES }, { "listen", LISTEN }, { "loadbalance", LOADBALANCE }, { "log", LOG }, @@ -1814,6 +1836,7 @@ lookup(char *s) { "priority", PRIORITY }, { "protocol", PROTO }, { "query", QUERYSTR }, + { "random", RANDOM }, { "real", REAL }, { "redirect", REDIRECT }, { "relay", RELAY }, @@ -1832,6 +1855,7 @@ lookup(char *s) { "send", SEND }, { "session", SESSION }, { "socket", SOCKET }, + { "source-hash", SRCHASH }, { "splice", SPLICE }, { "ssl", SSL }, { "sticky-address", STICKYADDR }, Index: pfe_filter.c =================================================================== RCS file: /cvs/src/usr.sbin/relayd/pfe_filter.c,v retrieving revision 1.51 diff -u -p -r1.51 pfe_filter.c --- pfe_filter.c 4 Oct 2012 20:53:30 -0000 1.51 +++ pfe_filter.c 15 Oct 2012 11:42:33 -0000 @@ -370,6 +370,7 @@ sync_ruleset(struct relayd *env, struct struct address *address; char anchor[PF_ANCHOR_NAME_SIZE]; struct table *t = rdr->table; + EVP_MD_CTX ctx; if ((env->sc_flags & F_NEEDPF) == 0) return; @@ -483,7 +484,30 @@ sync_ruleset(struct relayd *env, struct ntohs(rdr->table->conf.port); rio.rule.rdr.port_op = PF_OP_EQ; } - rio.rule.rdr.opts = PF_POOL_ROUNDROBIN; + + switch (rdr->conf.mode) { + case RELAY_DSTMODE_ROUNDROBIN: + rio.rule.rdr.opts = PF_POOL_ROUNDROBIN; + break; + case RELAY_DSTMODE_LEASTSTATES: + rio.rule.rdr.opts = PF_POOL_LEASTSTATES; + break; + case RELAY_DSTMODE_RANDOM: + rio.rule.rdr.opts = PF_POOL_RANDOM; + break; + case RELAY_DSTMODE_SRCHASH: + rio.rule.rdr.opts = PF_POOL_SRCHASH; + EVP_DigestInit(&ctx, EVP_md5()); + EVP_DigestUpdate(&ctx, rdr->conf.name, + strlen(rdr->conf.name)); + EVP_DigestUpdate(&ctx, rdr->table->conf.name, + strlen(rdr->table->conf.name)); + EVP_DigestFinal(&ctx, rio.rule.rdr.key.key8, NULL); + break; + default: + fatalx("sync_ruleset: unsupported mode"); + /* NOTREACHED */ + } if (rdr->conf.flags & F_STICKY) rio.rule.rdr.opts |= PF_POOL_STICKYADDR; Index: relay.c =================================================================== RCS file: /cvs/src/usr.sbin/relayd/relay.c,v retrieving revision 1.156 diff -u -p -r1.156 relay.c --- relay.c 4 Oct 2012 20:53:30 -0000 1.156 +++ relay.c 15 Oct 2012 11:42:33 -0000 @@ -387,10 +387,12 @@ relay_launch(void) TAILQ_FOREACH(rlt, &rlay->rl_tables, rlt_entry) { switch (rlt->rlt_mode) { case RELAY_DSTMODE_ROUNDROBIN: + case RELAY_DSTMODE_RANDOM: rlt->rlt_key = 0; break; case RELAY_DSTMODE_LOADBALANCE: case RELAY_DSTMODE_HASH: + case RELAY_DSTMODE_SRCHASH: rlt->rlt_key = hash32_str(rlay->rl_conf.name, HASHINIT); rlt->rlt_key = @@ -1107,7 +1109,7 @@ relay_from_table(struct rsession *con) struct relay_table *rlt = NULL; struct table *table = NULL; u_int32_t p = con->se_hashkey; - int idx = 0; + int idx = -1; /* the table is already selected */ if (con->se_table != NULL) { @@ -1145,16 +1147,28 @@ relay_from_table(struct rsession *con) rlt->rlt_key = 0; idx = (int)rlt->rlt_key; break; + case RELAY_DSTMODE_RANDOM: + idx = (int)arc4random_uniform(rlt->rlt_nhosts); + break; + case RELAY_DSTMODE_SRCHASH: case RELAY_DSTMODE_LOADBALANCE: + /* Source IP address without port */ p = relay_hash_addr(&con->se_in.ss, p); + if (rlt->rlt_mode == RELAY_DSTMODE_SRCHASH) + break; /* FALLTHROUGH */ case RELAY_DSTMODE_HASH: + /* Local "destination" IP address and port */ p = relay_hash_addr(&rlay->rl_conf.ss, p); p = hash32_buf(&rlay->rl_conf.port, sizeof(rlay->rl_conf.port), p); - if ((idx = p % rlt->rlt_nhosts) >= RELAY_MAXHOSTS) - return (-1); + break; + default: + fatalx("relay_from_table: unsupported mode"); + /* NOTREACHED */ } + if (idx == -1 && (idx = p % rlt->rlt_nhosts) >= RELAY_MAXHOSTS) + return (-1); host = rlt->rlt_host[idx]; DPRINTF("%s: session %d: table %s host %s, p 0x%08x, idx %d", __func__, con->se_id, table->conf.name, host->conf.name, p, idx); Index: relayd.conf.5 =================================================================== RCS file: /cvs/src/usr.sbin/relayd/relayd.conf.5,v retrieving revision 1.130 diff -u -p -r1.130 relayd.conf.5 --- relayd.conf.5 3 Oct 2012 08:33:31 -0000 1.130 +++ relayd.conf.5 15 Oct 2012 11:42:34 -0000 @@ -385,7 +385,7 @@ host from the specified table: .Bl -tag -width Ds .It Ic mode hash Balances the outgoing connections across the active hosts based on the -hashed name of the relay, the hashed name of the table and the IP +hashed name of the relay, the hashed name of the table, and the IP address and port of the relay. Additional input can be fed into the hash by looking at HTTP headers and GET variables; @@ -393,15 +393,28 @@ see the .Sx PROTOCOLS section below. This mode is only supported by relays. +.It Ic mode least-states +Forward each outgoing connection to the active host with the least +active states in +.Xr pf 4 . +This mode is only supported by redirections. .It Ic mode loadbalance Balances the outgoing connections across the active hosts based on the -hashed name of the relay, the hashed name of the table, the IP -address and port of the relay and the IP address of the client. +hashed name of the relay, the hashed name of the table, the source IP +address of the client, and the IP address and port of the relay. This mode is only supported by relays. +.It Ic mode random +Distributes the outgoing connections randomly through all active hosts. +This mode is supported by redirections and relays. .It Ic mode roundrobin Distributes the outgoing connections using a round-robin scheduler through all active hosts. This is the default mode and will be used if no option has been specified. +This mode is supported by redirections and relays. +.It Ic mode source-hash +Balances the outgoing connections across the active hosts based on the +hashed name of the redirection or relay, the hashed name of the table, +and the source IP address of the client. This mode is supported by redirections and relays. .El .Sh REDIRECTIONS Index: relayd.h =================================================================== RCS file: /cvs/src/usr.sbin/relayd/relayd.h,v retrieving revision 1.161 diff -u -p -r1.161 relayd.h --- relayd.h 4 Oct 2012 20:53:30 -0000 1.161 +++ relayd.h 15 Oct 2012 11:42:34 -0000 @@ -414,6 +414,7 @@ struct rdr_config { in_port_t port; objid_t table_id; objid_t backup_id; + int mode; char name[SRV_NAME_SIZE]; char tag[TAG_NAME_SIZE]; struct timeval timeout; @@ -648,9 +649,12 @@ struct relay { TAILQ_HEAD(relaylist, relay); enum dstmode { - RELAY_DSTMODE_LOADBALANCE = 0, - RELAY_DSTMODE_ROUNDROBIN = 1, - RELAY_DSTMODE_HASH = 2 + RELAY_DSTMODE_LOADBALANCE = 0, + RELAY_DSTMODE_ROUNDROBIN, + RELAY_DSTMODE_HASH, + RELAY_DSTMODE_SRCHASH, + RELAY_DSTMODE_LEASTSTATES, + RELAY_DSTMODE_RANDOM }; #define RELAY_DSTMODE_DEFAULT RELAY_DSTMODE_ROUNDROBIN