diff options
author | Alexander Frolkin <avf@eldamar.org.uk> | 2013-09-27 06:06:23 -0400 |
---|---|---|
committer | Simon Horman <horms@verge.net.au> | 2013-10-14 21:54:50 -0400 |
commit | 1255ce5f10dbb4646c8d43b8d59faab48ae4a6b2 (patch) | |
tree | e9246035c427a2d5ea7e494cc1e7b080a1c30d25 | |
parent | 9e4e948a3edafd2b7f4dc14c395e146ffd0d9611 (diff) |
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>
-rw-r--r-- | net/netfilter/ipvs/ip_vs_sh.c | 39 |
1 files changed, 29 insertions, 10 deletions
diff --git a/net/netfilter/ipvs/ip_vs_sh.c b/net/netfilter/ipvs/ip_vs_sh.c index 3588faebe529..cc65b2f42cd4 100644 --- a/net/netfilter/ipvs/ip_vs_sh.c +++ b/net/netfilter/ipvs/ip_vs_sh.c | |||
@@ -115,27 +115,46 @@ ip_vs_sh_get(struct ip_vs_service *svc, struct ip_vs_sh_state *s, | |||
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 | static inline struct ip_vs_dest * | 124 | static inline struct ip_vs_dest * |
120 | ip_vs_sh_get_fallback(struct ip_vs_service *svc, struct ip_vs_sh_state *s, | 125 | ip_vs_sh_get_fallback(struct ip_vs_service *svc, struct ip_vs_sh_state *s, |
121 | const union nf_inet_addr *addr, __be16 port) | 126 | const union nf_inet_addr *addr, __be16 port) |
122 | { | 127 | { |
123 | unsigned int offset; | 128 | unsigned int offset, roffset; |
124 | unsigned int hash; | 129 | unsigned int hash, ihash; |
125 | struct ip_vs_dest *dest; | 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 | for (offset = 0; offset < IP_VS_SH_TAB_SIZE; offset++) { | 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 | dest = rcu_dereference(s->buckets[hash].dest); | 149 | dest = rcu_dereference(s->buckets[hash].dest); |
130 | if (!dest) | 150 | if (!dest) |
131 | break; | 151 | break; |
132 | if (is_unavailable(dest)) | 152 | 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 | ||
138 | return dest; | 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 | return NULL; | 160 | return NULL; |