MINOR: backend: implement random-based load balancing

For large farms where servers are regularly added or removed, picking
a random server from the pool can ensure faster load transitions than
when using round-robin and less traffic surges on the newly added
servers than when using leastconn.

This commit introduces "balance random". It internally uses a random as
the key to the consistent hashing mechanism, thus all features available
in consistent hashing such as weights and bounded load via hash-balance-
factor are usable. It is extremely convenient because one common concern
when using random is what happens when a server is hammered a bit too
much. Here that can trivially be avoided, like in the configuration below :

    backend bk0
        balance random
        hash-balance-factor 110
        server-template s 1-100 127.0.0.1:8000 check inter 1s

Note that while "balance random" internally relies on a hash algorithm,
it holds the same properties as round-robin and as such is compatible with
reusing an existing server connection with "option prefer-last-server".
diff --git a/src/backend.c b/src/backend.c
index 2b6167d..8473efb 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -513,6 +513,21 @@
 		return map_get_server_hash(px, hash);
 }
 
+/* random value  */
+static struct server *get_server_rnd(struct stream *s)
+{
+	unsigned int hash = 0;
+	struct proxy  *px = s->be;
+
+	/* tot_weight appears to mean srv_count */
+	if (px->lbprm.tot_weight == 0)
+		return NULL;
+
+	/* ensure all 32 bits are covered as long as RAND_MAX >= 65535 */
+	hash = ((uint64_t)random() * ((uint64_t)RAND_MAX + 1)) ^ random();
+	return chash_get_server_hash(px, hash);
+}
+
 /*
  * This function applies the load-balancing algorithm to the stream, as
  * defined by the backend it is assigned to. The stream is then marked as
@@ -615,7 +630,9 @@
 		case BE_LB_LKUP_CHTREE:
 		case BE_LB_LKUP_MAP:
 			if ((s->be->lbprm.algo & BE_LB_KIND) == BE_LB_KIND_RR) {
-				if (s->be->lbprm.algo & BE_LB_LKUP_CHTREE)
+				if ((s->be->lbprm.algo & BE_LB_PARM) == BE_LB_RR_RANDOM)
+					srv = get_server_rnd(s);
+				else if (s->be->lbprm.algo & BE_LB_LKUP_CHTREE)
 					srv = chash_get_next_server(s->be, prev_srv);
 				else
 					srv = map_get_server_rr(s->be, prev_srv);
@@ -1503,6 +1520,10 @@
 		curproxy->lbprm.algo &= ~BE_LB_ALGO;
 		curproxy->lbprm.algo |= BE_LB_ALGO_LC;
 	}
+	else if (!strcmp(args[0], "random")) {
+		curproxy->lbprm.algo &= ~BE_LB_ALGO;
+		curproxy->lbprm.algo |= BE_LB_ALGO_RND;
+	}
 	else if (!strcmp(args[0], "source")) {
 		curproxy->lbprm.algo &= ~BE_LB_ALGO;
 		curproxy->lbprm.algo |= BE_LB_ALGO_SH;