Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipvs: improved SH fallback strategy

Improve the SH fallback realserver selection strategy.

With sh and sh-fallback, if a realserver is down, this attempts to
distribute the traffic that would have gone to that server evenly
among the remaining servers.

Signed-off-by: Alexander Frolkin <avf@eldamar.org.uk>
Acked-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Simon Horman <horms@verge.net.au>

authored by

Alexander Frolkin and committed by
Simon Horman
1255ce5f 9e4e948a

+29 -10
+29 -10
net/netfilter/ipvs/ip_vs_sh.c
··· 115 115 } 116 116 117 117 118 - /* As ip_vs_sh_get, but with fallback if selected server is unavailable */ 118 + /* As ip_vs_sh_get, but with fallback if selected server is unavailable 119 + * 120 + * The fallback strategy loops around the table starting from a "random" 121 + * point (in fact, it is chosen to be the original hash value to make the 122 + * algorithm deterministic) to find a new server. 123 + */ 119 124 static inline struct ip_vs_dest * 120 125 ip_vs_sh_get_fallback(struct ip_vs_service *svc, struct ip_vs_sh_state *s, 121 126 const union nf_inet_addr *addr, __be16 port) 122 127 { 123 - unsigned int offset; 124 - unsigned int hash; 128 + unsigned int offset, roffset; 129 + unsigned int hash, ihash; 125 130 struct ip_vs_dest *dest; 126 131 132 + /* first try the dest it's supposed to go to */ 133 + ihash = ip_vs_sh_hashkey(svc->af, addr, port, 0); 134 + dest = rcu_dereference(s->buckets[ihash].dest); 135 + if (!dest) 136 + return NULL; 137 + if (!is_unavailable(dest)) 138 + return dest; 139 + 140 + IP_VS_DBG_BUF(6, "SH: selected unavailable server %s:%d, reselecting", 141 + IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port)); 142 + 143 + /* if the original dest is unavailable, loop around the table 144 + * starting from ihash to find a new dest 145 + */ 127 146 for (offset = 0; offset < IP_VS_SH_TAB_SIZE; offset++) { 128 - hash = ip_vs_sh_hashkey(svc->af, addr, port, offset); 147 + roffset = (offset + ihash) % IP_VS_SH_TAB_SIZE; 148 + hash = ip_vs_sh_hashkey(svc->af, addr, port, roffset); 129 149 dest = rcu_dereference(s->buckets[hash].dest); 130 150 if (!dest) 131 151 break; 132 - if (is_unavailable(dest)) 133 - IP_VS_DBG_BUF(6, "SH: selected unavailable server " 134 - "%s:%d (offset %d)", 135 - IP_VS_DBG_ADDR(svc->af, &dest->addr), 136 - ntohs(dest->port), offset); 137 - else 152 + if (!is_unavailable(dest)) 138 153 return dest; 154 + IP_VS_DBG_BUF(6, "SH: selected unavailable " 155 + "server %s:%d (offset %d), reselecting", 156 + IP_VS_DBG_ADDR(svc->af, &dest->addr), 157 + ntohs(dest->port), roffset); 139 158 } 140 159 141 160 return NULL;