blob: 648d79747850cc41d6773c481e438bfbab14804b [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * Backend variables and functions.
3 *
Willy Tarreaue8c66af2008-01-13 18:40:14 +01004 * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
Willy Tarreaubaaee002006-06-26 02:48:02 +02005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <errno.h>
14#include <fcntl.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <syslog.h>
Willy Tarreauf19cf372006-11-14 15:40:51 +010018#include <string.h>
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +020019#include <ctype.h>
Dmitry Sivachenkocaf58982009-08-24 15:11:06 +040020#include <sys/types.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020021
Willy Tarreau2dd0d472006-06-29 17:53:05 +020022#include <common/compat.h>
Willy Tarreaue3ba5f02006-06-29 18:54:54 +020023#include <common/config.h>
Willy Tarreau7c669d72008-06-20 15:04:11 +020024#include <common/debug.h>
Willy Tarreaub625a082007-11-26 01:15:43 +010025#include <common/eb32tree.h>
Willy Tarreau0c303ee2008-07-07 00:09:58 +020026#include <common/ticks.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020027#include <common/time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020028
Willy Tarreaubaaee002006-06-26 02:48:02 +020029#include <types/global.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020030
Willy Tarreaua9d3c1e2007-11-30 20:48:53 +010031#include <proto/acl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020032#include <proto/backend.h>
Willy Tarreau14c8aac2007-05-08 19:46:30 +020033#include <proto/client.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020034#include <proto/proto_http.h>
Willy Tarreaue8c66af2008-01-13 18:40:14 +010035#include <proto/proto_tcp.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020036#include <proto/queue.h>
Willy Tarreau7f062c42009-03-05 18:43:00 +010037#include <proto/server.h>
Willy Tarreau7c669d72008-06-20 15:04:11 +020038#include <proto/session.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020039#include <proto/task.h>
40
Willy Tarreaub625a082007-11-26 01:15:43 +010041static inline void fwrr_remove_from_tree(struct server *s);
42static inline void fwrr_queue_by_weight(struct eb_root *root, struct server *s);
43static inline void fwrr_dequeue_srv(struct server *s);
44static void fwrr_get_srv(struct server *s);
45static void fwrr_queue_srv(struct server *s);
46
Willy Tarreaubaaee002006-06-26 02:48:02 +020047/*
48 * This function recounts the number of usable active and backup servers for
49 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
Willy Tarreaub625a082007-11-26 01:15:43 +010050 * This function also recomputes the total active and backup weights. However,
Willy Tarreauf4cca452008-03-08 21:42:54 +010051 * it does not update tot_weight nor tot_used. Use update_backend_weight() for
Willy Tarreaub625a082007-11-26 01:15:43 +010052 * this.
Willy Tarreaubaaee002006-06-26 02:48:02 +020053 */
Willy Tarreauc5d9c802009-10-01 09:17:05 +020054void recount_servers(struct proxy *px)
Willy Tarreaubaaee002006-06-26 02:48:02 +020055{
56 struct server *srv;
57
Willy Tarreau20697042007-11-15 23:26:18 +010058 px->srv_act = px->srv_bck = 0;
59 px->lbprm.tot_wact = px->lbprm.tot_wbck = 0;
Willy Tarreaub625a082007-11-26 01:15:43 +010060 px->lbprm.fbck = NULL;
Willy Tarreaubaaee002006-06-26 02:48:02 +020061 for (srv = px->srv; srv != NULL; srv = srv->next) {
Willy Tarreaub625a082007-11-26 01:15:43 +010062 if (!srv_is_usable(srv->state, srv->eweight))
63 continue;
64
65 if (srv->state & SRV_BACKUP) {
66 if (!px->srv_bck &&
Willy Tarreauf4cca452008-03-08 21:42:54 +010067 !(px->options & PR_O_USE_ALL_BK))
Willy Tarreaub625a082007-11-26 01:15:43 +010068 px->lbprm.fbck = srv;
69 px->srv_bck++;
70 px->lbprm.tot_wbck += srv->eweight;
71 } else {
72 px->srv_act++;
73 px->lbprm.tot_wact += srv->eweight;
Willy Tarreaubaaee002006-06-26 02:48:02 +020074 }
75 }
Willy Tarreaub625a082007-11-26 01:15:43 +010076}
Willy Tarreau20697042007-11-15 23:26:18 +010077
Willy Tarreaub625a082007-11-26 01:15:43 +010078/* This function simply updates the backend's tot_weight and tot_used values
79 * after servers weights have been updated. It is designed to be used after
80 * recount_servers() or equivalent.
81 */
Willy Tarreauc5d9c802009-10-01 09:17:05 +020082void update_backend_weight(struct proxy *px)
Willy Tarreaub625a082007-11-26 01:15:43 +010083{
Willy Tarreau20697042007-11-15 23:26:18 +010084 if (px->srv_act) {
85 px->lbprm.tot_weight = px->lbprm.tot_wact;
86 px->lbprm.tot_used = px->srv_act;
87 }
Willy Tarreaub625a082007-11-26 01:15:43 +010088 else if (px->lbprm.fbck) {
89 /* use only the first backup server */
90 px->lbprm.tot_weight = px->lbprm.fbck->eweight;
91 px->lbprm.tot_used = 1;
Willy Tarreau20697042007-11-15 23:26:18 +010092 }
93 else {
Willy Tarreaub625a082007-11-26 01:15:43 +010094 px->lbprm.tot_weight = px->lbprm.tot_wbck;
95 px->lbprm.tot_used = px->srv_bck;
Willy Tarreau20697042007-11-15 23:26:18 +010096 }
Willy Tarreaub625a082007-11-26 01:15:43 +010097}
98
99/* this function updates the map according to server <srv>'s new state */
100static void map_set_server_status_down(struct server *srv)
101{
102 struct proxy *p = srv->proxy;
103
104 if (srv->state == srv->prev_state &&
105 srv->eweight == srv->prev_eweight)
106 return;
107
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100108 if (srv_is_usable(srv->state, srv->eweight))
109 goto out_update_state;
110
Willy Tarreaub625a082007-11-26 01:15:43 +0100111 /* FIXME: could be optimized since we know what changed */
112 recount_servers(p);
113 update_backend_weight(p);
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100114 p->lbprm.map.state |= PR_MAP_RECALC;
115 out_update_state:
Willy Tarreaub625a082007-11-26 01:15:43 +0100116 srv->prev_state = srv->state;
117 srv->prev_eweight = srv->eweight;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200118}
119
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100120/* This function updates the map according to server <srv>'s new state */
Willy Tarreaub625a082007-11-26 01:15:43 +0100121static void map_set_server_status_up(struct server *srv)
122{
123 struct proxy *p = srv->proxy;
124
125 if (srv->state == srv->prev_state &&
126 srv->eweight == srv->prev_eweight)
127 return;
128
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100129 if (!srv_is_usable(srv->state, srv->eweight))
130 goto out_update_state;
131
Willy Tarreaub625a082007-11-26 01:15:43 +0100132 /* FIXME: could be optimized since we know what changed */
133 recount_servers(p);
134 update_backend_weight(p);
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100135 p->lbprm.map.state |= PR_MAP_RECALC;
136 out_update_state:
Willy Tarreaub625a082007-11-26 01:15:43 +0100137 srv->prev_state = srv->state;
138 srv->prev_eweight = srv->eweight;
Willy Tarreaub625a082007-11-26 01:15:43 +0100139}
140
Willy Tarreau20697042007-11-15 23:26:18 +0100141/* This function recomputes the server map for proxy px. It relies on
142 * px->lbprm.tot_wact, tot_wbck, tot_used, tot_weight, so it must be
143 * called after recount_servers(). It also expects px->lbprm.map.srv
144 * to be allocated with the largest size needed. It updates tot_weight.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200145 */
146void recalc_server_map(struct proxy *px)
147{
148 int o, tot, flag;
149 struct server *cur, *best;
150
Willy Tarreau20697042007-11-15 23:26:18 +0100151 switch (px->lbprm.tot_used) {
152 case 0: /* no server */
153 px->lbprm.map.state &= ~PR_MAP_RECALC;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200154 return;
Willy Tarreau20697042007-11-15 23:26:18 +0100155 case 1: /* only one server, just fill first entry */
156 tot = 1;
157 break;
158 default:
159 tot = px->lbprm.tot_weight;
160 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200161 }
162
Willy Tarreau20697042007-11-15 23:26:18 +0100163 /* here we *know* that we have some servers */
164 if (px->srv_act)
165 flag = SRV_RUNNING;
166 else
167 flag = SRV_RUNNING | SRV_BACKUP;
168
Willy Tarreaubaaee002006-06-26 02:48:02 +0200169 /* this algorithm gives priority to the first server, which means that
170 * it will respect the declaration order for equivalent weights, and
171 * that whatever the weights, the first server called will always be
Willy Tarreau20697042007-11-15 23:26:18 +0100172 * the first declared. This is an important asumption for the backup
Willy Tarreaubaaee002006-06-26 02:48:02 +0200173 * case, where we want the first server only.
174 */
175 for (cur = px->srv; cur; cur = cur->next)
176 cur->wscore = 0;
177
178 for (o = 0; o < tot; o++) {
179 int max = 0;
180 best = NULL;
181 for (cur = px->srv; cur; cur = cur->next) {
Willy Tarreau6704d672009-06-15 10:56:05 +0200182 if (cur->eweight &&
183 flag == (cur->state &
Willy Tarreau48494c02007-11-30 10:41:39 +0100184 (SRV_RUNNING | SRV_GOINGDOWN | SRV_BACKUP))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200185 int v;
186
187 /* If we are forced to return only one server, we don't want to
188 * go further, because we would return the wrong one due to
189 * divide overflow.
190 */
191 if (tot == 1) {
192 best = cur;
Willy Tarreau20697042007-11-15 23:26:18 +0100193 /* note that best->wscore will be wrong but we don't care */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200194 break;
195 }
196
Willy Tarreau417fae02007-03-25 21:16:40 +0200197 cur->wscore += cur->eweight;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200198 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
199 if (best == NULL || v > max) {
200 max = v;
201 best = cur;
202 }
203 }
204 }
Willy Tarreau20697042007-11-15 23:26:18 +0100205 px->lbprm.map.srv[o] = best;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200206 best->wscore -= tot;
207 }
Willy Tarreau20697042007-11-15 23:26:18 +0100208 px->lbprm.map.state &= ~PR_MAP_RECALC;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200209}
210
Willy Tarreau5dc2fa62007-11-19 19:10:18 +0100211/* This function is responsible of building the server MAP for map-based LB
212 * algorithms, allocating the map, and setting p->lbprm.wmult to the GCD of the
213 * weights if applicable. It should be called only once per proxy, at config
214 * time.
215 */
216void init_server_map(struct proxy *p)
217{
218 struct server *srv;
219 int pgcd;
220 int act, bck;
221
Willy Tarreaub625a082007-11-26 01:15:43 +0100222 p->lbprm.set_server_status_up = map_set_server_status_up;
223 p->lbprm.set_server_status_down = map_set_server_status_down;
224 p->lbprm.update_server_eweight = NULL;
225
Willy Tarreau5dc2fa62007-11-19 19:10:18 +0100226 if (!p->srv)
227 return;
228
229 /* We will factor the weights to reduce the table,
Willy Tarreau6704d672009-06-15 10:56:05 +0200230 * using Euclide's largest common divisor algorithm.
231 * Since we may have zero weights, we have to first
232 * find a non-zero weight server.
Willy Tarreau5dc2fa62007-11-19 19:10:18 +0100233 */
Willy Tarreau6704d672009-06-15 10:56:05 +0200234 pgcd = 1;
235 srv = p->srv;
236 while (srv && !srv->uweight)
237 srv = srv->next;
238
239 if (srv) {
240 pgcd = srv->uweight; /* note: cannot be zero */
241 while (pgcd > 1 && (srv = srv->next)) {
242 int w = srv->uweight;
243 while (w) {
244 int t = pgcd % w;
245 pgcd = w;
246 w = t;
247 }
Willy Tarreau5dc2fa62007-11-19 19:10:18 +0100248 }
249 }
250
251 /* It is sometimes useful to know what factor to apply
252 * to the backend's effective weight to know its real
253 * weight.
254 */
255 p->lbprm.wmult = pgcd;
256
257 act = bck = 0;
258 for (srv = p->srv; srv; srv = srv->next) {
259 srv->eweight = srv->uweight / pgcd;
Willy Tarreaub625a082007-11-26 01:15:43 +0100260 srv->prev_eweight = srv->eweight;
261 srv->prev_state = srv->state;
Willy Tarreau5dc2fa62007-11-19 19:10:18 +0100262 if (srv->state & SRV_BACKUP)
263 bck += srv->eweight;
264 else
265 act += srv->eweight;
266 }
267
268 /* this is the largest map we will ever need for this servers list */
269 if (act < bck)
270 act = bck;
271
Willy Tarreau6704d672009-06-15 10:56:05 +0200272 if (!act)
273 act = 1;
274
Willy Tarreau5dc2fa62007-11-19 19:10:18 +0100275 p->lbprm.map.srv = (struct server **)calloc(act, sizeof(struct server *));
276 /* recounts servers and their weights */
277 p->lbprm.map.state = PR_MAP_RECALC;
278 recount_servers(p);
Willy Tarreaub625a082007-11-26 01:15:43 +0100279 update_backend_weight(p);
Willy Tarreau5dc2fa62007-11-19 19:10:18 +0100280 recalc_server_map(p);
281}
282
Willy Tarreaub625a082007-11-26 01:15:43 +0100283/* This function updates the server trees according to server <srv>'s new
284 * state. It should be called when server <srv>'s status changes to down.
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100285 * It is not important whether the server was already down or not. It is not
286 * important either that the new state is completely down (the caller may not
287 * know all the variables of a server's state).
Willy Tarreaub625a082007-11-26 01:15:43 +0100288 */
289static void fwrr_set_server_status_down(struct server *srv)
290{
291 struct proxy *p = srv->proxy;
292 struct fwrr_group *grp;
293
294 if (srv->state == srv->prev_state &&
295 srv->eweight == srv->prev_eweight)
296 return;
297
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100298 if (srv_is_usable(srv->state, srv->eweight))
299 goto out_update_state;
300
Willy Tarreaub625a082007-11-26 01:15:43 +0100301 if (!srv_is_usable(srv->prev_state, srv->prev_eweight))
302 /* server was already down */
303 goto out_update_backend;
304
305 grp = (srv->state & SRV_BACKUP) ? &p->lbprm.fwrr.bck : &p->lbprm.fwrr.act;
306 grp->next_weight -= srv->prev_eweight;
307
308 if (srv->state & SRV_BACKUP) {
309 p->lbprm.tot_wbck = p->lbprm.fwrr.bck.next_weight;
310 p->srv_bck--;
311
312 if (srv == p->lbprm.fbck) {
313 /* we lost the first backup server in a single-backup
314 * configuration, we must search another one.
315 */
316 struct server *srv2 = p->lbprm.fbck;
317 do {
318 srv2 = srv2->next;
319 } while (srv2 &&
320 !((srv2->state & SRV_BACKUP) &&
321 srv_is_usable(srv2->state, srv2->eweight)));
322 p->lbprm.fbck = srv2;
323 }
324 } else {
325 p->lbprm.tot_wact = p->lbprm.fwrr.act.next_weight;
326 p->srv_act--;
327 }
328
329 fwrr_dequeue_srv(srv);
330 fwrr_remove_from_tree(srv);
331
332out_update_backend:
333 /* check/update tot_used, tot_weight */
334 update_backend_weight(p);
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100335 out_update_state:
Willy Tarreaub625a082007-11-26 01:15:43 +0100336 srv->prev_state = srv->state;
337 srv->prev_eweight = srv->eweight;
Willy Tarreaub625a082007-11-26 01:15:43 +0100338}
339
340/* This function updates the server trees according to server <srv>'s new
341 * state. It should be called when server <srv>'s status changes to up.
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100342 * It is not important whether the server was already down or not. It is not
343 * important either that the new state is completely UP (the caller may not
344 * know all the variables of a server's state). This function will not change
Willy Tarreaub625a082007-11-26 01:15:43 +0100345 * the weight of a server which was already up.
346 */
347static void fwrr_set_server_status_up(struct server *srv)
348{
349 struct proxy *p = srv->proxy;
350 struct fwrr_group *grp;
351
352 if (srv->state == srv->prev_state &&
353 srv->eweight == srv->prev_eweight)
354 return;
355
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100356 if (!srv_is_usable(srv->state, srv->eweight))
357 goto out_update_state;
358
Willy Tarreaub625a082007-11-26 01:15:43 +0100359 if (srv_is_usable(srv->prev_state, srv->prev_eweight))
360 /* server was already up */
361 goto out_update_backend;
362
363 grp = (srv->state & SRV_BACKUP) ? &p->lbprm.fwrr.bck : &p->lbprm.fwrr.act;
364 grp->next_weight += srv->eweight;
365
366 if (srv->state & SRV_BACKUP) {
367 p->lbprm.tot_wbck = p->lbprm.fwrr.bck.next_weight;
368 p->srv_bck++;
369
Willy Tarreauf4cca452008-03-08 21:42:54 +0100370 if (!(p->options & PR_O_USE_ALL_BK)) {
371 if (!p->lbprm.fbck) {
372 /* there was no backup server anymore */
Willy Tarreaub625a082007-11-26 01:15:43 +0100373 p->lbprm.fbck = srv;
Willy Tarreauf4cca452008-03-08 21:42:54 +0100374 } else {
375 /* we may have restored a backup server prior to fbck,
376 * in which case it should replace it.
377 */
378 struct server *srv2 = srv;
379 do {
380 srv2 = srv2->next;
381 } while (srv2 && (srv2 != p->lbprm.fbck));
382 if (srv2)
383 p->lbprm.fbck = srv;
384 }
Willy Tarreaub625a082007-11-26 01:15:43 +0100385 }
386 } else {
387 p->lbprm.tot_wact = p->lbprm.fwrr.act.next_weight;
388 p->srv_act++;
389 }
390
391 /* note that eweight cannot be 0 here */
392 fwrr_get_srv(srv);
393 srv->npos = grp->curr_pos + (grp->next_weight + grp->curr_weight - grp->curr_pos) / srv->eweight;
394 fwrr_queue_srv(srv);
395
396out_update_backend:
397 /* check/update tot_used, tot_weight */
398 update_backend_weight(p);
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100399 out_update_state:
Willy Tarreaub625a082007-11-26 01:15:43 +0100400 srv->prev_state = srv->state;
401 srv->prev_eweight = srv->eweight;
402}
403
404/* This function must be called after an update to server <srv>'s effective
405 * weight. It may be called after a state change too.
406 */
407static void fwrr_update_server_weight(struct server *srv)
408{
409 int old_state, new_state;
410 struct proxy *p = srv->proxy;
411 struct fwrr_group *grp;
412
413 if (srv->state == srv->prev_state &&
414 srv->eweight == srv->prev_eweight)
415 return;
416
417 /* If changing the server's weight changes its state, we simply apply
418 * the procedures we already have for status change. If the state
419 * remains down, the server is not in any tree, so it's as easy as
420 * updating its values. If the state remains up with different weights,
421 * there are some computations to perform to find a new place and
422 * possibly a new tree for this server.
423 */
424
425 old_state = srv_is_usable(srv->prev_state, srv->prev_eweight);
426 new_state = srv_is_usable(srv->state, srv->eweight);
427
428 if (!old_state && !new_state) {
429 srv->prev_state = srv->state;
430 srv->prev_eweight = srv->eweight;
431 return;
432 }
433 else if (!old_state && new_state) {
434 fwrr_set_server_status_up(srv);
435 return;
436 }
437 else if (old_state && !new_state) {
438 fwrr_set_server_status_down(srv);
439 return;
440 }
441
442 grp = (srv->state & SRV_BACKUP) ? &p->lbprm.fwrr.bck : &p->lbprm.fwrr.act;
443 grp->next_weight = grp->next_weight - srv->prev_eweight + srv->eweight;
444
445 p->lbprm.tot_wact = p->lbprm.fwrr.act.next_weight;
446 p->lbprm.tot_wbck = p->lbprm.fwrr.bck.next_weight;
447
448 if (srv->lb_tree == grp->init) {
449 fwrr_dequeue_srv(srv);
450 fwrr_queue_by_weight(grp->init, srv);
451 }
452 else if (!srv->lb_tree) {
453 /* FIXME: server was down. This is not possible right now but
454 * may be needed soon for slowstart or graceful shutdown.
455 */
456 fwrr_dequeue_srv(srv);
457 fwrr_get_srv(srv);
458 srv->npos = grp->curr_pos + (grp->next_weight + grp->curr_weight - grp->curr_pos) / srv->eweight;
459 fwrr_queue_srv(srv);
460 } else {
461 /* The server is either active or in the next queue. If it's
462 * still in the active queue and it has not consumed all of its
463 * places, let's adjust its next position.
464 */
465 fwrr_get_srv(srv);
466
467 if (srv->eweight > 0) {
468 int prev_next = srv->npos;
469 int step = grp->next_weight / srv->eweight;
470
471 srv->npos = srv->lpos + step;
472 srv->rweight = 0;
473
474 if (srv->npos > prev_next)
475 srv->npos = prev_next;
476 if (srv->npos < grp->curr_pos + 2)
477 srv->npos = grp->curr_pos + step;
478 } else {
479 /* push it into the next tree */
480 srv->npos = grp->curr_pos + grp->curr_weight;
481 }
482
483 fwrr_dequeue_srv(srv);
484 fwrr_queue_srv(srv);
485 }
486
487 update_backend_weight(p);
488 srv->prev_state = srv->state;
489 srv->prev_eweight = srv->eweight;
490}
491
492/* Remove a server from a tree. It must have previously been dequeued. This
493 * function is meant to be called when a server is going down or has its
494 * weight disabled.
495 */
496static inline void fwrr_remove_from_tree(struct server *s)
497{
498 s->lb_tree = NULL;
499}
500
501/* Queue a server in the weight tree <root>, assuming the weight is >0.
502 * We want to sort them by inverted weights, because we need to place
503 * heavy servers first in order to get a smooth distribution.
504 */
505static inline void fwrr_queue_by_weight(struct eb_root *root, struct server *s)
506{
Willy Tarreaub698f0f2007-12-02 11:01:23 +0100507 s->lb_node.key = SRV_EWGHT_MAX - s->eweight;
Willy Tarreaub625a082007-11-26 01:15:43 +0100508 eb32_insert(root, &s->lb_node);
509 s->lb_tree = root;
510}
511
512/* This function is responsible for building the weight trees in case of fast
513 * weighted round-robin. It also sets p->lbprm.wdiv to the eweight to uweight
514 * ratio. Both active and backup groups are initialized.
515 */
516void fwrr_init_server_groups(struct proxy *p)
517{
518 struct server *srv;
519 struct eb_root init_head = EB_ROOT;
520
521 p->lbprm.set_server_status_up = fwrr_set_server_status_up;
522 p->lbprm.set_server_status_down = fwrr_set_server_status_down;
523 p->lbprm.update_server_eweight = fwrr_update_server_weight;
524
525 p->lbprm.wdiv = BE_WEIGHT_SCALE;
526 for (srv = p->srv; srv; srv = srv->next) {
527 srv->prev_eweight = srv->eweight = srv->uweight * BE_WEIGHT_SCALE;
528 srv->prev_state = srv->state;
529 }
530
531 recount_servers(p);
532 update_backend_weight(p);
533
534 /* prepare the active servers group */
535 p->lbprm.fwrr.act.curr_pos = p->lbprm.fwrr.act.curr_weight =
536 p->lbprm.fwrr.act.next_weight = p->lbprm.tot_wact;
537 p->lbprm.fwrr.act.curr = p->lbprm.fwrr.act.t0 =
538 p->lbprm.fwrr.act.t1 = init_head;
539 p->lbprm.fwrr.act.init = &p->lbprm.fwrr.act.t0;
540 p->lbprm.fwrr.act.next = &p->lbprm.fwrr.act.t1;
541
542 /* prepare the backup servers group */
543 p->lbprm.fwrr.bck.curr_pos = p->lbprm.fwrr.bck.curr_weight =
544 p->lbprm.fwrr.bck.next_weight = p->lbprm.tot_wbck;
545 p->lbprm.fwrr.bck.curr = p->lbprm.fwrr.bck.t0 =
546 p->lbprm.fwrr.bck.t1 = init_head;
547 p->lbprm.fwrr.bck.init = &p->lbprm.fwrr.bck.t0;
548 p->lbprm.fwrr.bck.next = &p->lbprm.fwrr.bck.t1;
549
550 /* queue active and backup servers in two distinct groups */
551 for (srv = p->srv; srv; srv = srv->next) {
552 if (!srv_is_usable(srv->state, srv->eweight))
553 continue;
554 fwrr_queue_by_weight((srv->state & SRV_BACKUP) ?
555 p->lbprm.fwrr.bck.init :
556 p->lbprm.fwrr.act.init,
557 srv);
558 }
559}
560
561/* simply removes a server from a weight tree */
562static inline void fwrr_dequeue_srv(struct server *s)
563{
564 eb32_delete(&s->lb_node);
565}
566
567/* queues a server into the appropriate group and tree depending on its
568 * backup status, and ->npos. If the server is disabled, simply assign
569 * it to the NULL tree.
570 */
571static void fwrr_queue_srv(struct server *s)
572{
573 struct proxy *p = s->proxy;
574 struct fwrr_group *grp;
575
576 grp = (s->state & SRV_BACKUP) ? &p->lbprm.fwrr.bck : &p->lbprm.fwrr.act;
577
578 /* Delay everything which does not fit into the window and everything
579 * which does not fit into the theorical new window.
580 */
581 if (!srv_is_usable(s->state, s->eweight)) {
582 fwrr_remove_from_tree(s);
583 }
584 else if (s->eweight <= 0 ||
585 s->npos >= 2 * grp->curr_weight ||
586 s->npos >= grp->curr_weight + grp->next_weight) {
587 /* put into next tree, and readjust npos in case we could
588 * finally take this back to current. */
589 s->npos -= grp->curr_weight;
590 fwrr_queue_by_weight(grp->next, s);
591 }
592 else {
Willy Tarreaub698f0f2007-12-02 11:01:23 +0100593 /* The sorting key is stored in units of s->npos * user_weight
594 * in order to avoid overflows. As stated in backend.h, the
595 * lower the scale, the rougher the weights modulation, and the
596 * higher the scale, the lower the number of servers without
597 * overflow. With this formula, the result is always positive,
598 * so we can use eb3é_insert().
Willy Tarreaub625a082007-11-26 01:15:43 +0100599 */
Willy Tarreaub698f0f2007-12-02 11:01:23 +0100600 s->lb_node.key = SRV_UWGHT_RANGE * s->npos +
601 (unsigned)(SRV_EWGHT_MAX + s->rweight - s->eweight) / BE_WEIGHT_SCALE;
602
603 eb32_insert(&grp->curr, &s->lb_node);
Willy Tarreaub625a082007-11-26 01:15:43 +0100604 s->lb_tree = &grp->curr;
605 }
606}
607
608/* prepares a server when extracting it from the "init" tree */
609static inline void fwrr_get_srv_init(struct server *s)
610{
611 s->npos = s->rweight = 0;
612}
613
614/* prepares a server when extracting it from the "next" tree */
615static inline void fwrr_get_srv_next(struct server *s)
616{
617 struct fwrr_group *grp = (s->state & SRV_BACKUP) ?
618 &s->proxy->lbprm.fwrr.bck :
619 &s->proxy->lbprm.fwrr.act;
620
621 s->npos += grp->curr_weight;
622}
623
624/* prepares a server when it was marked down */
625static inline void fwrr_get_srv_down(struct server *s)
626{
627 struct fwrr_group *grp = (s->state & SRV_BACKUP) ?
628 &s->proxy->lbprm.fwrr.bck :
629 &s->proxy->lbprm.fwrr.act;
630
631 s->npos = grp->curr_pos;
632}
633
634/* prepares a server when extracting it from its tree */
635static void fwrr_get_srv(struct server *s)
636{
637 struct proxy *p = s->proxy;
638 struct fwrr_group *grp = (s->state & SRV_BACKUP) ?
639 &p->lbprm.fwrr.bck :
640 &p->lbprm.fwrr.act;
641
642 if (s->lb_tree == grp->init) {
643 fwrr_get_srv_init(s);
644 }
645 else if (s->lb_tree == grp->next) {
646 fwrr_get_srv_next(s);
647 }
648 else if (s->lb_tree == NULL) {
649 fwrr_get_srv_down(s);
650 }
651}
652
653/* switches trees "init" and "next" for FWRR group <grp>. "init" should be empty
654 * when this happens, and "next" filled with servers sorted by weights.
655 */
656static inline void fwrr_switch_trees(struct fwrr_group *grp)
657{
658 struct eb_root *swap;
659 swap = grp->init;
660 grp->init = grp->next;
661 grp->next = swap;
662 grp->curr_weight = grp->next_weight;
663 grp->curr_pos = grp->curr_weight;
664}
665
666/* return next server from the current tree in FWRR group <grp>, or a server
667 * from the "init" tree if appropriate. If both trees are empty, return NULL.
668 */
669static struct server *fwrr_get_server_from_group(struct fwrr_group *grp)
670{
671 struct eb32_node *node;
672 struct server *s;
673
674 node = eb32_first(&grp->curr);
675 s = eb32_entry(node, struct server, lb_node);
676
677 if (!node || s->npos > grp->curr_pos) {
678 /* either we have no server left, or we have a hole */
679 struct eb32_node *node2;
680 node2 = eb32_first(grp->init);
681 if (node2) {
682 node = node2;
683 s = eb32_entry(node, struct server, lb_node);
684 fwrr_get_srv_init(s);
685 if (s->eweight == 0) /* FIXME: is it possible at all ? */
686 node = NULL;
687 }
688 }
689 if (node)
690 return s;
691 else
692 return NULL;
693}
694
695/* Computes next position of server <s> in the group. It is mandatory for <s>
696 * to have a non-zero, positive eweight.
697*/
698static inline void fwrr_update_position(struct fwrr_group *grp, struct server *s)
699{
700 if (!s->npos) {
701 /* first time ever for this server */
702 s->lpos = grp->curr_pos;
703 s->npos = grp->curr_pos + grp->next_weight / s->eweight;
704 s->rweight += grp->next_weight % s->eweight;
705
706 if (s->rweight >= s->eweight) {
707 s->rweight -= s->eweight;
708 s->npos++;
709 }
710 } else {
711 s->lpos = s->npos;
712 s->npos += grp->next_weight / s->eweight;
713 s->rweight += grp->next_weight % s->eweight;
714
715 if (s->rweight >= s->eweight) {
716 s->rweight -= s->eweight;
717 s->npos++;
718 }
719 }
720}
721
722/* Return next server from the current tree in backend <p>, or a server from
723 * the init tree if appropriate. If both trees are empty, return NULL.
724 * Saturated servers are skipped and requeued.
725 */
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100726static struct server *fwrr_get_next_server(struct proxy *p, struct server *srvtoavoid)
Willy Tarreaub625a082007-11-26 01:15:43 +0100727{
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100728 struct server *srv, *full, *avoided;
Willy Tarreaub625a082007-11-26 01:15:43 +0100729 struct fwrr_group *grp;
Willy Tarreaub625a082007-11-26 01:15:43 +0100730 int switched;
731
732 if (p->srv_act)
733 grp = &p->lbprm.fwrr.act;
734 else if (p->lbprm.fbck)
735 return p->lbprm.fbck;
736 else if (p->srv_bck)
737 grp = &p->lbprm.fwrr.bck;
738 else
739 return NULL;
740
741 switched = 0;
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100742 avoided = NULL;
Willy Tarreaub625a082007-11-26 01:15:43 +0100743 full = NULL; /* NULL-terminated list of saturated servers */
744 while (1) {
745 /* if we see an empty group, let's first try to collect weights
746 * which might have recently changed.
747 */
748 if (!grp->curr_weight)
749 grp->curr_pos = grp->curr_weight = grp->next_weight;
750
751 /* get first server from the "current" tree. When the end of
752 * the tree is reached, we may have to switch, but only once.
753 */
754 while (1) {
755 srv = fwrr_get_server_from_group(grp);
756 if (srv)
757 break;
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100758 if (switched) {
759 if (avoided) {
760 srv = avoided;
761 break;
762 }
Willy Tarreaub625a082007-11-26 01:15:43 +0100763 goto requeue_servers;
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100764 }
Willy Tarreaub625a082007-11-26 01:15:43 +0100765 switched = 1;
766 fwrr_switch_trees(grp);
767
768 }
769
770 /* OK, we have a server. However, it may be saturated, in which
771 * case we don't want to reconsider it for now. We'll update
772 * its position and dequeue it anyway, so that we can move it
773 * to a better place afterwards.
774 */
775 fwrr_update_position(grp, srv);
776 fwrr_dequeue_srv(srv);
777 grp->curr_pos++;
Willy Tarreau7c669d72008-06-20 15:04:11 +0200778 if (!srv->maxconn || (!srv->nbpend && srv->served < srv_dynamic_maxconn(srv))) {
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100779 /* make sure it is not the server we are trying to exclude... */
780 if (srv != srvtoavoid || avoided)
781 break;
782
783 avoided = srv; /* ...but remember that is was selected yet avoided */
784 }
Willy Tarreaub625a082007-11-26 01:15:43 +0100785
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100786 /* the server is saturated or avoided, let's chain it for later reinsertion */
Willy Tarreaub625a082007-11-26 01:15:43 +0100787 srv->next_full = full;
788 full = srv;
789 }
790
791 /* OK, we got the best server, let's update it */
792 fwrr_queue_srv(srv);
793
794 requeue_servers:
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100795 /* Requeue all extracted servers. If full==srv then it was
796 * avoided (unsucessfully) and chained, omit it now.
797 */
Willy Tarreau70bcfb72008-01-27 02:21:53 +0100798 if (unlikely(full != NULL)) {
Willy Tarreaub625a082007-11-26 01:15:43 +0100799 if (switched) {
800 /* the tree has switched, requeue all extracted servers
801 * into "init", because their place was lost, and only
802 * their weight matters.
803 */
804 do {
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100805 if (likely(full != srv))
806 fwrr_queue_by_weight(grp->init, full);
Willy Tarreaub625a082007-11-26 01:15:43 +0100807 full = full->next_full;
808 } while (full);
809 } else {
810 /* requeue all extracted servers just as if they were consumed
811 * so that they regain their expected place.
812 */
813 do {
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100814 if (likely(full != srv))
815 fwrr_queue_srv(full);
Willy Tarreaub625a082007-11-26 01:15:43 +0100816 full = full->next_full;
817 } while (full);
818 }
819 }
820 return srv;
821}
822
Willy Tarreau51406232008-03-10 22:04:20 +0100823/* Remove a server from a tree. It must have previously been dequeued. This
824 * function is meant to be called when a server is going down or has its
825 * weight disabled.
826 */
827static inline void fwlc_remove_from_tree(struct server *s)
828{
829 s->lb_tree = NULL;
830}
831
832/* simply removes a server from a tree */
833static inline void fwlc_dequeue_srv(struct server *s)
834{
835 eb32_delete(&s->lb_node);
836}
837
838/* Queue a server in its associated tree, assuming the weight is >0.
839 * Servers are sorted by #conns/weight. To ensure maximum accuracy,
840 * we use #conns*SRV_EWGHT_MAX/eweight as the sorting key.
841 */
842static inline void fwlc_queue_srv(struct server *s)
843{
Willy Tarreau7c669d72008-06-20 15:04:11 +0200844 s->lb_node.key = s->served * SRV_EWGHT_MAX / s->eweight;
Willy Tarreau51406232008-03-10 22:04:20 +0100845 eb32_insert(s->lb_tree, &s->lb_node);
846}
847
848/* Re-position the server in the FWLC tree after it has been assigned one
849 * connection or after it has released one. Note that it is possible that
850 * the server has been moved out of the tree due to failed health-checks.
851 */
852static void fwlc_srv_reposition(struct server *s)
853{
854 if (!s->lb_tree)
855 return;
856 fwlc_dequeue_srv(s);
857 fwlc_queue_srv(s);
858}
859
860/* This function updates the server trees according to server <srv>'s new
861 * state. It should be called when server <srv>'s status changes to down.
862 * It is not important whether the server was already down or not. It is not
863 * important either that the new state is completely down (the caller may not
864 * know all the variables of a server's state).
865 */
866static void fwlc_set_server_status_down(struct server *srv)
867{
868 struct proxy *p = srv->proxy;
869
870 if (srv->state == srv->prev_state &&
871 srv->eweight == srv->prev_eweight)
872 return;
873
874 if (srv_is_usable(srv->state, srv->eweight))
875 goto out_update_state;
876
877 if (!srv_is_usable(srv->prev_state, srv->prev_eweight))
878 /* server was already down */
879 goto out_update_backend;
880
881 if (srv->state & SRV_BACKUP) {
882 p->lbprm.tot_wbck -= srv->prev_eweight;
883 p->srv_bck--;
884
885 if (srv == p->lbprm.fbck) {
886 /* we lost the first backup server in a single-backup
887 * configuration, we must search another one.
888 */
889 struct server *srv2 = p->lbprm.fbck;
890 do {
891 srv2 = srv2->next;
892 } while (srv2 &&
893 !((srv2->state & SRV_BACKUP) &&
894 srv_is_usable(srv2->state, srv2->eweight)));
895 p->lbprm.fbck = srv2;
896 }
897 } else {
898 p->lbprm.tot_wact -= srv->prev_eweight;
899 p->srv_act--;
900 }
901
902 fwlc_dequeue_srv(srv);
903 fwlc_remove_from_tree(srv);
904
905out_update_backend:
906 /* check/update tot_used, tot_weight */
907 update_backend_weight(p);
908 out_update_state:
909 srv->prev_state = srv->state;
910 srv->prev_eweight = srv->eweight;
911}
912
913/* This function updates the server trees according to server <srv>'s new
914 * state. It should be called when server <srv>'s status changes to up.
915 * It is not important whether the server was already down or not. It is not
916 * important either that the new state is completely UP (the caller may not
917 * know all the variables of a server's state). This function will not change
918 * the weight of a server which was already up.
919 */
920static void fwlc_set_server_status_up(struct server *srv)
921{
922 struct proxy *p = srv->proxy;
923
924 if (srv->state == srv->prev_state &&
925 srv->eweight == srv->prev_eweight)
926 return;
927
928 if (!srv_is_usable(srv->state, srv->eweight))
929 goto out_update_state;
930
931 if (srv_is_usable(srv->prev_state, srv->prev_eweight))
932 /* server was already up */
933 goto out_update_backend;
934
935 if (srv->state & SRV_BACKUP) {
936 srv->lb_tree = &p->lbprm.fwlc.bck;
937 p->lbprm.tot_wbck += srv->eweight;
938 p->srv_bck++;
939
940 if (!(p->options & PR_O_USE_ALL_BK)) {
941 if (!p->lbprm.fbck) {
942 /* there was no backup server anymore */
943 p->lbprm.fbck = srv;
944 } else {
945 /* we may have restored a backup server prior to fbck,
946 * in which case it should replace it.
947 */
948 struct server *srv2 = srv;
949 do {
950 srv2 = srv2->next;
951 } while (srv2 && (srv2 != p->lbprm.fbck));
952 if (srv2)
953 p->lbprm.fbck = srv;
954 }
955 }
956 } else {
957 srv->lb_tree = &p->lbprm.fwlc.act;
958 p->lbprm.tot_wact += srv->eweight;
959 p->srv_act++;
960 }
961
962 /* note that eweight cannot be 0 here */
963 fwlc_queue_srv(srv);
964
965 out_update_backend:
966 /* check/update tot_used, tot_weight */
967 update_backend_weight(p);
968 out_update_state:
969 srv->prev_state = srv->state;
970 srv->prev_eweight = srv->eweight;
971}
972
973/* This function must be called after an update to server <srv>'s effective
974 * weight. It may be called after a state change too.
975 */
976static void fwlc_update_server_weight(struct server *srv)
977{
978 int old_state, new_state;
979 struct proxy *p = srv->proxy;
980
981 if (srv->state == srv->prev_state &&
982 srv->eweight == srv->prev_eweight)
983 return;
984
985 /* If changing the server's weight changes its state, we simply apply
986 * the procedures we already have for status change. If the state
987 * remains down, the server is not in any tree, so it's as easy as
988 * updating its values. If the state remains up with different weights,
989 * there are some computations to perform to find a new place and
990 * possibly a new tree for this server.
991 */
992
993 old_state = srv_is_usable(srv->prev_state, srv->prev_eweight);
994 new_state = srv_is_usable(srv->state, srv->eweight);
995
996 if (!old_state && !new_state) {
997 srv->prev_state = srv->state;
998 srv->prev_eweight = srv->eweight;
999 return;
1000 }
1001 else if (!old_state && new_state) {
1002 fwlc_set_server_status_up(srv);
1003 return;
1004 }
1005 else if (old_state && !new_state) {
1006 fwlc_set_server_status_down(srv);
1007 return;
1008 }
1009
1010 if (srv->lb_tree)
1011 fwlc_dequeue_srv(srv);
1012
1013 if (srv->state & SRV_BACKUP) {
1014 p->lbprm.tot_wbck += srv->eweight - srv->prev_eweight;
1015 srv->lb_tree = &p->lbprm.fwlc.bck;
1016 } else {
1017 p->lbprm.tot_wact += srv->eweight - srv->prev_eweight;
1018 srv->lb_tree = &p->lbprm.fwlc.act;
1019 }
1020
1021 fwlc_queue_srv(srv);
1022
1023 update_backend_weight(p);
1024 srv->prev_state = srv->state;
1025 srv->prev_eweight = srv->eweight;
1026}
1027
1028/* This function is responsible for building the trees in case of fast
1029 * weighted least-conns. It also sets p->lbprm.wdiv to the eweight to
1030 * uweight ratio. Both active and backup groups are initialized.
1031 */
1032void fwlc_init_server_tree(struct proxy *p)
1033{
1034 struct server *srv;
1035 struct eb_root init_head = EB_ROOT;
1036
1037 p->lbprm.set_server_status_up = fwlc_set_server_status_up;
1038 p->lbprm.set_server_status_down = fwlc_set_server_status_down;
1039 p->lbprm.update_server_eweight = fwlc_update_server_weight;
1040 p->lbprm.server_take_conn = fwlc_srv_reposition;
1041 p->lbprm.server_drop_conn = fwlc_srv_reposition;
1042
1043 p->lbprm.wdiv = BE_WEIGHT_SCALE;
1044 for (srv = p->srv; srv; srv = srv->next) {
1045 srv->prev_eweight = srv->eweight = srv->uweight * BE_WEIGHT_SCALE;
1046 srv->prev_state = srv->state;
1047 }
1048
1049 recount_servers(p);
1050 update_backend_weight(p);
1051
1052 p->lbprm.fwlc.act = init_head;
1053 p->lbprm.fwlc.bck = init_head;
1054
1055 /* queue active and backup servers in two distinct groups */
1056 for (srv = p->srv; srv; srv = srv->next) {
1057 if (!srv_is_usable(srv->state, srv->eweight))
1058 continue;
1059 srv->lb_tree = (srv->state & SRV_BACKUP) ? &p->lbprm.fwlc.bck : &p->lbprm.fwlc.act;
1060 fwlc_queue_srv(srv);
1061 }
1062}
1063
1064/* Return next server from the FWLC tree in backend <p>. If the tree is empty,
1065 * return NULL. Saturated servers are skipped.
1066 */
1067static struct server *fwlc_get_next_server(struct proxy *p, struct server *srvtoavoid)
1068{
1069 struct server *srv, *avoided;
1070 struct eb32_node *node;
1071
1072 srv = avoided = NULL;
1073
1074 if (p->srv_act)
1075 node = eb32_first(&p->lbprm.fwlc.act);
1076 else if (p->lbprm.fbck)
1077 return p->lbprm.fbck;
1078 else if (p->srv_bck)
1079 node = eb32_first(&p->lbprm.fwlc.bck);
1080 else
1081 return NULL;
1082
1083 while (node) {
1084 /* OK, we have a server. However, it may be saturated, in which
1085 * case we don't want to reconsider it for now, so we'll simply
1086 * skip it. Same if it's the server we try to avoid, in which
1087 * case we simply remember it for later use if needed.
1088 */
1089 struct server *s;
1090
1091 s = eb32_entry(node, struct server, lb_node);
Willy Tarreau7c669d72008-06-20 15:04:11 +02001092 if (!s->maxconn || (!s->nbpend && s->served < srv_dynamic_maxconn(s))) {
Willy Tarreau51406232008-03-10 22:04:20 +01001093 if (s != srvtoavoid) {
1094 srv = s;
1095 break;
1096 }
1097 avoided = s;
1098 }
1099 node = eb32_next(node);
1100 }
1101
1102 if (!srv)
1103 srv = avoided;
1104
1105 return srv;
1106}
1107
Willy Tarreau01732802007-11-01 22:48:15 +01001108/*
1109 * This function tries to find a running server for the proxy <px> following
1110 * the URL parameter hash method. It looks for a specific parameter in the
1111 * URL and hashes it to compute the server ID. This is useful to optimize
1112 * performance by avoiding bounces between servers in contexts where sessions
1113 * are shared but cookies are not usable. If the parameter is not found, NULL
1114 * is returned. If any server is found, it will be returned. If no valid server
1115 * is found, NULL is returned.
Willy Tarreau01732802007-11-01 22:48:15 +01001116 */
1117struct server *get_server_ph(struct proxy *px, const char *uri, int uri_len)
1118{
1119 unsigned long hash = 0;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001120 const char *p;
1121 const char *params;
Willy Tarreau01732802007-11-01 22:48:15 +01001122 int plen;
1123
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001124 /* when tot_weight is 0 then so is srv_count */
Willy Tarreau20697042007-11-15 23:26:18 +01001125 if (px->lbprm.tot_weight == 0)
Willy Tarreau01732802007-11-01 22:48:15 +01001126 return NULL;
1127
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001128 if ((p = memchr(uri, '?', uri_len)) == NULL)
1129 return NULL;
1130
Willy Tarreau20697042007-11-15 23:26:18 +01001131 if (px->lbprm.map.state & PR_MAP_RECALC)
1132 recalc_server_map(px);
1133
Willy Tarreau01732802007-11-01 22:48:15 +01001134 p++;
1135
1136 uri_len -= (p - uri);
1137 plen = px->url_param_len;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001138 params = p;
Willy Tarreau01732802007-11-01 22:48:15 +01001139
1140 while (uri_len > plen) {
1141 /* Look for the parameter name followed by an equal symbol */
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001142 if (params[plen] == '=') {
1143 if (memcmp(params, px->url_param_name, plen) == 0) {
1144 /* OK, we have the parameter here at <params>, and
Willy Tarreau01732802007-11-01 22:48:15 +01001145 * the value after the equal sign, at <p>
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001146 * skip the equal symbol
Willy Tarreau01732802007-11-01 22:48:15 +01001147 */
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001148 p += plen + 1;
1149 uri_len -= plen + 1;
1150
Willy Tarreau01732802007-11-01 22:48:15 +01001151 while (uri_len && *p != '&') {
1152 hash = *p + (hash << 6) + (hash << 16) - hash;
1153 uri_len--;
1154 p++;
1155 }
Willy Tarreau20697042007-11-15 23:26:18 +01001156 return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
Willy Tarreau01732802007-11-01 22:48:15 +01001157 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001158 }
1159 /* skip to next parameter */
1160 p = memchr(params, '&', uri_len);
1161 if (!p)
1162 return NULL;
1163 p++;
1164 uri_len -= (p - params);
1165 params = p;
1166 }
1167 return NULL;
1168}
1169
1170/*
1171 * this does the same as the previous server_ph, but check the body contents
1172 */
1173struct server *get_server_ph_post(struct session *s)
1174{
1175 unsigned long hash = 0;
1176 struct http_txn *txn = &s->txn;
1177 struct buffer *req = s->req;
1178 struct http_msg *msg = &txn->req;
1179 struct proxy *px = s->be;
1180 unsigned int plen = px->url_param_len;
Willy Tarreau192ee3e2008-04-19 21:24:56 +02001181 unsigned long body;
1182 unsigned long len;
1183 const char *params;
1184 struct hdr_ctx ctx;
1185 const char *p;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001186
1187 /* tot_weight appears to mean srv_count */
1188 if (px->lbprm.tot_weight == 0)
1189 return NULL;
1190
Willy Tarreau192ee3e2008-04-19 21:24:56 +02001191 body = msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1;
Willy Tarreaufb0528b2008-08-11 00:21:56 +02001192 len = req->l - body;
Willy Tarreau192ee3e2008-04-19 21:24:56 +02001193 params = req->data + body;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001194
1195 if ( len == 0 )
1196 return NULL;
1197
1198 if (px->lbprm.map.state & PR_MAP_RECALC)
1199 recalc_server_map(px);
1200
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001201 ctx.idx = 0;
1202
1203 /* if the message is chunked, we skip the chunk size, but use the value as len */
1204 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
Willy Tarreauadfb8562008-08-11 15:24:42 +02001205 if (ctx.idx && ctx.vlen >= 7 && strncasecmp(ctx.line+ctx.val, "chunked", 7) == 0) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001206 unsigned int chunk = 0;
Willy Tarreau03d60bb2009-01-09 11:13:00 +01001207 while ( params < (req->data+req->max_len) && !HTTP_IS_CRLF(*params)) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001208 char c = *params;
1209 if (ishex(c)) {
1210 unsigned int hex = toupper(c) - '0';
1211 if ( hex > 9 )
1212 hex -= 'A' - '9' - 1;
1213 chunk = (chunk << 4) | hex;
1214 }
1215 else
1216 return NULL;
1217 params++;
1218 len--;
Willy Tarreau01732802007-11-01 22:48:15 +01001219 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001220 /* spec says we get CRLF */
1221 if (HTTP_IS_CRLF(*params) && HTTP_IS_CRLF(params[1]))
1222 params += 2;
1223 else
1224 return NULL;
1225 /* ok we have some encoded length, just inspect the first chunk */
1226 len = chunk;
1227 }
Willy Tarreau01732802007-11-01 22:48:15 +01001228
Willy Tarreau192ee3e2008-04-19 21:24:56 +02001229 p = params;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001230
1231 while (len > plen) {
1232 /* Look for the parameter name followed by an equal symbol */
1233 if (params[plen] == '=') {
1234 if (memcmp(params, px->url_param_name, plen) == 0) {
1235 /* OK, we have the parameter here at <params>, and
1236 * the value after the equal sign, at <p>
1237 * skip the equal symbol
1238 */
1239 p += plen + 1;
1240 len -= plen + 1;
1241
1242 while (len && *p != '&') {
1243 if (unlikely(!HTTP_IS_TOKEN(*p))) {
1244 /* if in a POST, body must be URI encoded or its not a URI.
1245 * Do not interprete any possible binary data as a parameter.
1246 */
1247 if (likely(HTTP_IS_LWS(*p))) /* eol, uncertain uri len */
1248 break;
1249 return NULL; /* oh, no; this is not uri-encoded.
1250 * This body does not contain parameters.
1251 */
1252 }
1253 hash = *p + (hash << 6) + (hash << 16) - hash;
1254 len--;
1255 p++;
1256 /* should we break if vlen exceeds limit? */
1257 }
1258 return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
1259 }
1260 }
Willy Tarreau01732802007-11-01 22:48:15 +01001261 /* skip to next parameter */
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001262 p = memchr(params, '&', len);
Willy Tarreau01732802007-11-01 22:48:15 +01001263 if (!p)
1264 return NULL;
1265 p++;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001266 len -= (p - params);
1267 params = p;
Willy Tarreau01732802007-11-01 22:48:15 +01001268 }
1269 return NULL;
1270}
Willy Tarreaubaaee002006-06-26 02:48:02 +02001271
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001272
Willy Tarreaubaaee002006-06-26 02:48:02 +02001273/*
Benoitaffb4812009-03-25 13:02:10 +01001274 * This function tries to find a running server for the proxy <px> following
1275 * the Header parameter hash method. It looks for a specific parameter in the
1276 * URL and hashes it to compute the server ID. This is useful to optimize
1277 * performance by avoiding bounces between servers in contexts where sessions
1278 * are shared but cookies are not usable. If the parameter is not found, NULL
1279 * is returned. If any server is found, it will be returned. If no valid server
1280 * is found, NULL is returned.
1281 */
1282struct server *get_server_hh(struct session *s)
1283{
1284 unsigned long hash = 0;
1285 struct http_txn *txn = &s->txn;
1286 struct http_msg *msg = &txn->req;
1287 struct proxy *px = s->be;
1288 unsigned int plen = px->hh_len;
1289 unsigned long len;
1290 struct hdr_ctx ctx;
1291 const char *p;
1292
1293 /* tot_weight appears to mean srv_count */
1294 if (px->lbprm.tot_weight == 0)
1295 return NULL;
1296
1297 if (px->lbprm.map.state & PR_MAP_RECALC)
1298 recalc_server_map(px);
1299
1300 ctx.idx = 0;
1301
1302 /* if the message is chunked, we skip the chunk size, but use the value as len */
1303 http_find_header2(px->hh_name, plen, msg->sol, &txn->hdr_idx, &ctx);
1304
1305 /* if the header is not found or empty, let's fallback to round robin */
1306 if (!ctx.idx || !ctx.vlen)
1307 return NULL;
1308
1309 /* Found a the hh_name in the headers.
1310 * we will compute the hash based on this value ctx.val.
1311 */
1312 len = ctx.vlen;
1313 p = (char *)ctx.line + ctx.val;
1314 if (!px->hh_match_domain) {
1315 while (len) {
1316 hash = *p + (hash << 6) + (hash << 16) - hash;
1317 len--;
1318 p++;
1319 }
1320 } else {
1321 int dohash = 0;
1322 p += len - 1;
1323 /* special computation, use only main domain name, not tld/host
1324 * going back from the end of string, start hashing at first
1325 * dot stop at next.
1326 * This is designed to work with the 'Host' header, and requires
1327 * a special option to activate this.
1328 */
1329 while (len) {
1330 if (*p == '.') {
1331 if (!dohash)
1332 dohash = 1;
1333 else
1334 break;
1335 } else {
1336 if (dohash)
1337 hash = *p + (hash << 6) + (hash << 16) - hash;
1338 }
1339 len--;
1340 p--;
1341 }
1342 }
1343 return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
1344}
1345
Emeric Brun736aa232009-06-30 17:56:00 +02001346struct server *get_server_rch(struct session *s)
1347{
1348 unsigned long hash = 0;
1349 struct proxy *px = s->be;
1350 unsigned long len;
1351 const char *p;
1352 int ret;
1353 struct acl_expr expr;
1354 struct acl_test test;
1355
1356 /* tot_weight appears to mean srv_count */
1357 if (px->lbprm.tot_weight == 0)
1358 return NULL;
1359
1360 if (px->lbprm.map.state & PR_MAP_RECALC)
1361 recalc_server_map(px);
1362
1363 memset(&expr, 0, sizeof(expr));
1364 memset(&test, 0, sizeof(test));
1365
1366 expr.arg.str = px->hh_name;
1367 expr.arg_len = px->hh_len;
1368
1369 ret = acl_fetch_rdp_cookie(px, s, NULL, ACL_DIR_REQ, &expr, &test);
1370 if (ret == 0 || (test.flags & ACL_TEST_F_MAY_CHANGE) || test.len == 0)
1371 return NULL;
1372
1373 /* Found a the hh_name in the headers.
1374 * we will compute the hash based on this value ctx.val.
1375 */
1376 len = test.len;
1377 p = (char *)test.ptr;
1378 while (len) {
1379 hash = *p + (hash << 6) + (hash << 16) - hash;
1380 len--;
1381 p++;
1382 }
1383
1384 return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
1385}
Benoitaffb4812009-03-25 13:02:10 +01001386
1387/*
Willy Tarreau7c669d72008-06-20 15:04:11 +02001388 * This function applies the load-balancing algorithm to the session, as
1389 * defined by the backend it is assigned to. The session is then marked as
1390 * 'assigned'.
1391 *
1392 * This function MAY NOT be called with SN_ASSIGNED already set. If the session
1393 * had a server previously assigned, it is rebalanced, trying to avoid the same
1394 * server.
1395 * The function tries to keep the original connection slot if it reconnects to
1396 * the same server, otherwise it releases it and tries to offer it.
1397 *
1398 * It is illegal to call this function with a session in a queue.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001399 *
1400 * It may return :
Willy Tarreau7c669d72008-06-20 15:04:11 +02001401 * SRV_STATUS_OK if everything is OK. Session assigned to ->srv
1402 * SRV_STATUS_NOSRV if no server is available. Session is not ASSIGNED
1403 * SRV_STATUS_FULL if all servers are saturated. Session is not ASSIGNED
Willy Tarreaubaaee002006-06-26 02:48:02 +02001404 * SRV_STATUS_INTERNAL for other unrecoverable errors.
1405 *
Willy Tarreau7c669d72008-06-20 15:04:11 +02001406 * Upon successful return, the session flag SN_ASSIGNED is set to indicate that
1407 * it does not need to be called anymore. This means that s->srv can be trusted
1408 * in balance and direct modes.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001409 *
1410 */
1411
1412int assign_server(struct session *s)
1413{
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001414
Willy Tarreau7c669d72008-06-20 15:04:11 +02001415 struct server *conn_slot;
1416 int err;
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001417
Willy Tarreaubaaee002006-06-26 02:48:02 +02001418#ifdef DEBUG_FULL
1419 fprintf(stderr,"assign_server : s=%p\n",s);
1420#endif
1421
Willy Tarreau7c669d72008-06-20 15:04:11 +02001422 err = SRV_STATUS_INTERNAL;
1423 if (unlikely(s->pend_pos || s->flags & SN_ASSIGNED))
1424 goto out_err;
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001425
Willy Tarreau7c669d72008-06-20 15:04:11 +02001426 s->prev_srv = s->prev_srv;
1427 conn_slot = s->srv_conn;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001428
Willy Tarreau7c669d72008-06-20 15:04:11 +02001429 /* We have to release any connection slot before applying any LB algo,
1430 * otherwise we may erroneously end up with no available slot.
1431 */
1432 if (conn_slot)
1433 sess_change_server(s, NULL);
1434
1435 /* We will now try to find the good server and store it into <s->srv>.
1436 * Note that <s->srv> may be NULL in case of dispatch or proxy mode,
1437 * as well as if no server is available (check error code).
1438 */
Willy Tarreau1a20a5d2007-11-01 21:08:19 +01001439
Willy Tarreau7c669d72008-06-20 15:04:11 +02001440 s->srv = NULL;
1441 if (s->be->lbprm.algo & BE_LB_ALGO) {
1442 int len;
1443 /* we must check if we have at least one server available */
1444 if (!s->be->lbprm.tot_weight) {
1445 err = SRV_STATUS_NOSRV;
1446 goto out;
1447 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001448
Willy Tarreau7c669d72008-06-20 15:04:11 +02001449 switch (s->be->lbprm.algo & BE_LB_ALGO) {
1450 case BE_LB_ALGO_RR:
1451 s->srv = fwrr_get_next_server(s->be, s->prev_srv);
1452 if (!s->srv) {
1453 err = SRV_STATUS_FULL;
1454 goto out;
1455 }
1456 break;
1457 case BE_LB_ALGO_LC:
1458 s->srv = fwlc_get_next_server(s->be, s->prev_srv);
1459 if (!s->srv) {
1460 err = SRV_STATUS_FULL;
1461 goto out;
1462 }
1463 break;
1464 case BE_LB_ALGO_SH:
1465 if (s->cli_addr.ss_family == AF_INET)
1466 len = 4;
1467 else if (s->cli_addr.ss_family == AF_INET6)
1468 len = 16;
1469 else {
1470 /* unknown IP family */
1471 err = SRV_STATUS_INTERNAL;
1472 goto out;
1473 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001474
Willy Tarreau7c669d72008-06-20 15:04:11 +02001475 s->srv = get_server_sh(s->be,
1476 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
1477 len);
1478 break;
1479 case BE_LB_ALGO_UH:
1480 /* URI hashing */
1481 s->srv = get_server_uh(s->be,
1482 s->txn.req.sol + s->txn.req.sl.rq.u,
1483 s->txn.req.sl.rq.u_l);
1484 break;
1485 case BE_LB_ALGO_PH:
1486 /* URL Parameter hashing */
1487 if (s->txn.meth == HTTP_METH_POST &&
1488 memchr(s->txn.req.sol + s->txn.req.sl.rq.u, '&',
1489 s->txn.req.sl.rq.u_l ) == NULL)
1490 s->srv = get_server_ph_post(s);
1491 else
1492 s->srv = get_server_ph(s->be,
Willy Tarreau2fcb5002007-05-08 13:35:26 +02001493 s->txn.req.sol + s->txn.req.sl.rq.u,
1494 s->txn.req.sl.rq.u_l);
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001495
Willy Tarreau7c669d72008-06-20 15:04:11 +02001496 if (!s->srv) {
1497 /* parameter not found, fall back to round robin on the map */
1498 s->srv = get_server_rr_with_conns(s->be, s->prev_srv);
Willy Tarreau01732802007-11-01 22:48:15 +01001499 if (!s->srv) {
Willy Tarreau7c669d72008-06-20 15:04:11 +02001500 err = SRV_STATUS_FULL;
1501 goto out;
Willy Tarreau01732802007-11-01 22:48:15 +01001502 }
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001503 }
Willy Tarreau7c669d72008-06-20 15:04:11 +02001504 break;
Benoitaffb4812009-03-25 13:02:10 +01001505 case BE_LB_ALGO_HH:
1506 /* Header Parameter hashing */
1507 s->srv = get_server_hh(s);
1508
1509 if (!s->srv) {
1510 /* parameter not found, fall back to round robin on the map */
1511 s->srv = get_server_rr_with_conns(s->be, s->prev_srv);
1512 if (!s->srv) {
1513 err = SRV_STATUS_FULL;
1514 goto out;
1515 }
1516 }
1517 break;
Emeric Brun736aa232009-06-30 17:56:00 +02001518 case BE_LB_ALGO_RCH:
1519 /* RDP Cookie hashing */
1520 s->srv = get_server_rch(s);
1521
1522 if (!s->srv) {
1523 /* parameter not found, fall back to round robin on the map */
1524 s->srv = get_server_rr_with_conns(s->be, s->prev_srv);
1525 if (!s->srv) {
1526 err = SRV_STATUS_FULL;
1527 goto out;
1528 }
1529 }
1530 break;
Willy Tarreau7c669d72008-06-20 15:04:11 +02001531 default:
1532 /* unknown balancing algorithm */
1533 err = SRV_STATUS_INTERNAL;
1534 goto out;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001535 }
Willy Tarreau7c669d72008-06-20 15:04:11 +02001536 if (s->srv != s->prev_srv) {
1537 s->be->cum_lbconn++;
1538 s->srv->cum_lbconn++;
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01001539 }
Willy Tarreau7c669d72008-06-20 15:04:11 +02001540 }
1541 else if (s->be->options & PR_O_HTTP_PROXY) {
1542 if (!s->srv_addr.sin_addr.s_addr) {
1543 err = SRV_STATUS_NOSRV;
1544 goto out;
Willy Tarreau5d65bbb2007-01-21 12:47:26 +01001545 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001546 }
Willy Tarreau7c669d72008-06-20 15:04:11 +02001547 else if (!*(int *)&s->be->dispatch_addr.sin_addr &&
Willy Tarreau4b1f8592008-12-23 23:13:55 +01001548 !(s->be->options & PR_O_TRANSP)) {
Willy Tarreau7c669d72008-06-20 15:04:11 +02001549 err = SRV_STATUS_NOSRV;
1550 goto out;
1551 }
1552
1553 s->flags |= SN_ASSIGNED;
1554 err = SRV_STATUS_OK;
1555 out:
1556
1557 /* Either we take back our connection slot, or we offer it to someone
1558 * else if we don't need it anymore.
1559 */
1560 if (conn_slot) {
1561 if (conn_slot == s->srv) {
1562 sess_change_server(s, s->srv);
1563 } else {
1564 if (may_dequeue_tasks(conn_slot, s->be))
1565 process_srv_queue(conn_slot);
1566 }
1567 }
1568
1569 out_err:
1570 return err;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001571}
1572
1573
1574/*
1575 * This function assigns a server address to a session, and sets SN_ADDR_SET.
1576 * The address is taken from the currently assigned server, or from the
1577 * dispatch or transparent address.
1578 *
1579 * It may return :
1580 * SRV_STATUS_OK if everything is OK.
1581 * SRV_STATUS_INTERNAL for other unrecoverable errors.
1582 *
1583 * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
1584 * not cleared, so it's to the caller to clear it if required.
1585 *
1586 */
1587int assign_server_address(struct session *s)
1588{
1589#ifdef DEBUG_FULL
1590 fprintf(stderr,"assign_server_address : s=%p\n",s);
1591#endif
1592
Willy Tarreau31682232007-11-29 15:38:04 +01001593 if ((s->flags & SN_DIRECT) || (s->be->lbprm.algo & BE_LB_ALGO)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001594 /* A server is necessarily known for this session */
1595 if (!(s->flags & SN_ASSIGNED))
1596 return SRV_STATUS_INTERNAL;
1597
1598 s->srv_addr = s->srv->addr;
1599
1600 /* if this server remaps proxied ports, we'll use
1601 * the port the client connected to with an offset. */
1602 if (s->srv->state & SRV_MAPPORTS) {
Willy Tarreau4b1f8592008-12-23 23:13:55 +01001603 if (!(s->be->options & PR_O_TRANSP) && !(s->flags & SN_FRT_ADDR_SET))
Willy Tarreau14c8aac2007-05-08 19:46:30 +02001604 get_frt_addr(s);
1605 if (s->frt_addr.ss_family == AF_INET) {
1606 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) +
1607 ntohs(((struct sockaddr_in *)&s->frt_addr)->sin_port));
1608 } else {
1609 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) +
1610 ntohs(((struct sockaddr_in6 *)&s->frt_addr)->sin6_port));
1611 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001612 }
1613 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001614 else if (*(int *)&s->be->dispatch_addr.sin_addr) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001615 /* connect to the defined dispatch addr */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001616 s->srv_addr = s->be->dispatch_addr;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001617 }
Willy Tarreau4b1f8592008-12-23 23:13:55 +01001618 else if (s->be->options & PR_O_TRANSP) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001619 /* in transparent mode, use the original dest addr if no dispatch specified */
Willy Tarreaubd414282008-01-19 13:46:35 +01001620 if (!(s->flags & SN_FRT_ADDR_SET))
1621 get_frt_addr(s);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001622
Willy Tarreaubd414282008-01-19 13:46:35 +01001623 memcpy(&s->srv_addr, &s->frt_addr, MIN(sizeof(s->srv_addr), sizeof(s->frt_addr)));
1624 /* when we support IPv6 on the backend, we may add other tests */
1625 //qfprintf(stderr, "Cannot get original server address.\n");
1626 //return SRV_STATUS_INTERNAL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001627 }
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01001628 else if (s->be->options & PR_O_HTTP_PROXY) {
1629 /* If HTTP PROXY option is set, then server is already assigned
1630 * during incoming client request parsing. */
1631 }
Willy Tarreau1a1158b2007-01-20 11:07:46 +01001632 else {
1633 /* no server and no LB algorithm ! */
1634 return SRV_STATUS_INTERNAL;
1635 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001636
1637 s->flags |= SN_ADDR_SET;
1638 return SRV_STATUS_OK;
1639}
1640
1641
1642/* This function assigns a server to session <s> if required, and can add the
1643 * connection to either the assigned server's queue or to the proxy's queue.
Willy Tarreau7c669d72008-06-20 15:04:11 +02001644 * If ->srv_conn is set, the session is first released from the server.
1645 * It may also be called with SN_DIRECT and/or SN_ASSIGNED though. It will
1646 * be called before any connection and after any retry or redispatch occurs.
1647 *
1648 * It is not allowed to call this function with a session in a queue.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001649 *
1650 * Returns :
1651 *
1652 * SRV_STATUS_OK if everything is OK.
1653 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
1654 * SRV_STATUS_QUEUED if the connection has been queued.
1655 * SRV_STATUS_FULL if the server(s) is/are saturated and the
Willy Tarreau7c669d72008-06-20 15:04:11 +02001656 * connection could not be queued in s->srv,
1657 * which may be NULL if we queue on the backend.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001658 * SRV_STATUS_INTERNAL for other unrecoverable errors.
1659 *
1660 */
1661int assign_server_and_queue(struct session *s)
1662{
1663 struct pendconn *p;
1664 int err;
1665
1666 if (s->pend_pos)
1667 return SRV_STATUS_INTERNAL;
1668
Willy Tarreau7c669d72008-06-20 15:04:11 +02001669 err = SRV_STATUS_OK;
1670 if (!(s->flags & SN_ASSIGNED)) {
1671 err = assign_server(s);
1672 if (s->prev_srv) {
1673 /* This session was previously assigned to a server. We have to
1674 * update the session's and the server's stats :
1675 * - if the server changed :
1676 * - set TX_CK_DOWN if txn.flags was TX_CK_VALID
1677 * - set SN_REDISP if it was successfully redispatched
1678 * - increment srv->redispatches and be->redispatches
1679 * - if the server remained the same : update retries.
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001680 */
1681
Willy Tarreau7c669d72008-06-20 15:04:11 +02001682 if (s->prev_srv != s->srv) {
1683 if ((s->txn.flags & TX_CK_MASK) == TX_CK_VALID) {
1684 s->txn.flags &= ~TX_CK_MASK;
1685 s->txn.flags |= TX_CK_DOWN;
1686 }
1687 s->flags |= SN_REDISP;
1688 s->prev_srv->redispatches++;
1689 s->be->redispatches++;
1690 } else {
1691 s->prev_srv->retries++;
1692 s->be->retries++;
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001693 }
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001694 }
1695 }
1696
Willy Tarreaubaaee002006-06-26 02:48:02 +02001697 switch (err) {
1698 case SRV_STATUS_OK:
Willy Tarreau7c669d72008-06-20 15:04:11 +02001699 /* we have SN_ASSIGNED set */
1700 if (!s->srv)
1701 return SRV_STATUS_OK; /* dispatch or proxy mode */
1702
1703 /* If we already have a connection slot, no need to check any queue */
1704 if (s->srv_conn == s->srv)
1705 return SRV_STATUS_OK;
1706
1707 /* OK, this session already has an assigned server, but no
1708 * connection slot yet. Either it is a redispatch, or it was
1709 * assigned from persistence information (direct mode).
1710 */
1711 if ((s->flags & SN_REDIRECTABLE) && s->srv->rdr_len) {
1712 /* server scheduled for redirection, and already assigned. We
1713 * don't want to go further nor check the queue.
Willy Tarreau21d2af32008-02-14 20:25:24 +01001714 */
Willy Tarreau7c669d72008-06-20 15:04:11 +02001715 sess_change_server(s, s->srv); /* not really needed in fact */
Willy Tarreau21d2af32008-02-14 20:25:24 +01001716 return SRV_STATUS_OK;
1717 }
1718
Willy Tarreau7c669d72008-06-20 15:04:11 +02001719 /* We might have to queue this session if the assigned server is full.
1720 * We know we have to queue it into the server's queue, so if a maxqueue
1721 * is set on the server, we must also check that the server's queue is
1722 * not full, in which case we have to return FULL.
1723 */
1724 if (s->srv->maxconn &&
1725 (s->srv->nbpend || s->srv->served >= srv_dynamic_maxconn(s->srv))) {
1726
1727 if (s->srv->maxqueue > 0 && s->srv->nbpend >= s->srv->maxqueue)
1728 return SRV_STATUS_FULL;
1729
Willy Tarreaubaaee002006-06-26 02:48:02 +02001730 p = pendconn_add(s);
1731 if (p)
1732 return SRV_STATUS_QUEUED;
1733 else
Willy Tarreau7c669d72008-06-20 15:04:11 +02001734 return SRV_STATUS_INTERNAL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001735 }
Willy Tarreau7c669d72008-06-20 15:04:11 +02001736
1737 /* OK, we can use this server. Let's reserve our place */
1738 sess_change_server(s, s->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001739 return SRV_STATUS_OK;
1740
1741 case SRV_STATUS_FULL:
1742 /* queue this session into the proxy's queue */
1743 p = pendconn_add(s);
1744 if (p)
1745 return SRV_STATUS_QUEUED;
1746 else
Willy Tarreau7c669d72008-06-20 15:04:11 +02001747 return SRV_STATUS_INTERNAL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001748
1749 case SRV_STATUS_NOSRV:
Willy Tarreau7c669d72008-06-20 15:04:11 +02001750 return err;
1751
Willy Tarreaubaaee002006-06-26 02:48:02 +02001752 case SRV_STATUS_INTERNAL:
1753 return err;
Willy Tarreau7c669d72008-06-20 15:04:11 +02001754
Willy Tarreaubaaee002006-06-26 02:48:02 +02001755 default:
1756 return SRV_STATUS_INTERNAL;
1757 }
Willy Tarreau5b6995c2008-01-13 16:31:17 +01001758}
Willy Tarreaubaaee002006-06-26 02:48:02 +02001759
1760/*
1761 * This function initiates a connection to the server assigned to this session
1762 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
1763 * It can return one of :
1764 * - SN_ERR_NONE if everything's OK
1765 * - SN_ERR_SRVTO if there are no more servers
1766 * - SN_ERR_SRVCL if the connection was refused by the server
1767 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1768 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1769 * - SN_ERR_INTERNAL for any other purely internal errors
1770 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
1771 */
1772int connect_server(struct session *s)
1773{
Willy Tarreau9650f372009-08-16 14:02:45 +02001774 int err;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001775
1776 if (!(s->flags & SN_ADDR_SET)) {
1777 err = assign_server_address(s);
1778 if (err != SRV_STATUS_OK)
1779 return SN_ERR_INTERNAL;
1780 }
1781
Willy Tarreau9650f372009-08-16 14:02:45 +02001782 if (!s->req->cons->connect)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001783 return SN_ERR_INTERNAL;
Willy Tarreaud88edf22009-06-14 15:48:17 +02001784
Willy Tarreau9650f372009-08-16 14:02:45 +02001785 err = s->req->cons->connect(s->req->cons, s->be, s->srv,
1786 (struct sockaddr *)&s->srv_addr,
1787 (struct sockaddr *)&s->cli_addr);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001788
Willy Tarreau9650f372009-08-16 14:02:45 +02001789 if (err != SN_ERR_NONE)
1790 return err;
Willy Tarreau788e2842008-08-26 13:25:39 +02001791
Willy Tarreaubaaee002006-06-26 02:48:02 +02001792 if (s->srv) {
Willy Tarreau1e62de62008-11-11 20:20:02 +01001793 s->flags |= SN_CURR_SESS;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001794 s->srv->cur_sess++;
1795 if (s->srv->cur_sess > s->srv->cur_sess_max)
1796 s->srv->cur_sess_max = s->srv->cur_sess;
Willy Tarreau51406232008-03-10 22:04:20 +01001797 if (s->be->lbprm.server_take_conn)
1798 s->be->lbprm.server_take_conn(s->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001799 }
1800
Willy Tarreaubaaee002006-06-26 02:48:02 +02001801 return SN_ERR_NONE; /* connection is OK */
1802}
1803
1804
Willy Tarreaubaaee002006-06-26 02:48:02 +02001805/* This function performs the "redispatch" part of a connection attempt. It
1806 * will assign a server if required, queue the connection if required, and
1807 * handle errors that might arise at this level. It can change the server
1808 * state. It will return 1 if it encounters an error, switches the server
1809 * state, or has to queue a connection. Otherwise, it will return 0 indicating
1810 * that the connection is ready to use.
1811 */
1812
1813int srv_redispatch_connect(struct session *t)
1814{
1815 int conn_err;
1816
1817 /* We know that we don't have any connection pending, so we will
1818 * try to get a new one, and wait in this state if it's queued
1819 */
Willy Tarreau7c669d72008-06-20 15:04:11 +02001820 redispatch:
Willy Tarreaubaaee002006-06-26 02:48:02 +02001821 conn_err = assign_server_and_queue(t);
1822 switch (conn_err) {
1823 case SRV_STATUS_OK:
1824 break;
1825
Willy Tarreau7c669d72008-06-20 15:04:11 +02001826 case SRV_STATUS_FULL:
1827 /* The server has reached its maxqueue limit. Either PR_O_REDISP is set
1828 * and we can redispatch to another server, or it is not and we return
1829 * 503. This only makes sense in DIRECT mode however, because normal LB
1830 * algorithms would never select such a server, and hash algorithms
1831 * would bring us on the same server again. Note that t->srv is set in
1832 * this case.
1833 */
1834 if ((t->flags & SN_DIRECT) && (t->be->options & PR_O_REDISP)) {
1835 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
1836 t->prev_srv = t->srv;
1837 goto redispatch;
1838 }
1839
Willy Tarreaufa7e1022008-10-19 07:30:41 +02001840 if (!t->req->cons->err_type) {
1841 t->req->cons->err_type = SI_ET_QUEUE_ERR;
1842 t->req->cons->err_loc = t->srv;
1843 }
Willy Tarreau7c669d72008-06-20 15:04:11 +02001844
1845 t->srv->failed_conns++;
1846 t->be->failed_conns++;
1847 return 1;
1848
Willy Tarreaubaaee002006-06-26 02:48:02 +02001849 case SRV_STATUS_NOSRV:
1850 /* note: it is guaranteed that t->srv == NULL here */
Willy Tarreaufa7e1022008-10-19 07:30:41 +02001851 if (!t->req->cons->err_type) {
1852 t->req->cons->err_type = SI_ET_CONN_ERR;
1853 t->req->cons->err_loc = NULL;
1854 }
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001855
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001856 t->be->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001857 return 1;
1858
1859 case SRV_STATUS_QUEUED:
Willy Tarreau35374672008-09-03 18:11:02 +02001860 t->req->cons->exp = tick_add_ifset(now_ms, t->be->timeout.queue);
Willy Tarreaufa7e1022008-10-19 07:30:41 +02001861 t->req->cons->state = SI_ST_QUE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001862 /* do nothing else and do not wake any other session up */
1863 return 1;
1864
Willy Tarreaubaaee002006-06-26 02:48:02 +02001865 case SRV_STATUS_INTERNAL:
1866 default:
Willy Tarreaufa7e1022008-10-19 07:30:41 +02001867 if (!t->req->cons->err_type) {
1868 t->req->cons->err_type = SI_ET_CONN_OTHER;
1869 t->req->cons->err_loc = t->srv;
1870 }
1871
Willy Tarreaubaaee002006-06-26 02:48:02 +02001872 if (t->srv)
Willy Tarreau7f062c42009-03-05 18:43:00 +01001873 srv_inc_sess_ctr(t->srv);
Willy Tarreau98937b82007-12-10 15:05:42 +01001874 if (t->srv)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001875 t->srv->failed_conns++;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001876 t->be->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001877
1878 /* release other sessions waiting for this server */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001879 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001880 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001881 return 1;
1882 }
1883 /* if we get here, it's because we got SRV_STATUS_OK, which also
1884 * means that the connection has not been queued.
1885 */
1886 return 0;
1887}
1888
Krzysztof Oledzki85130942007-10-22 16:21:10 +02001889int be_downtime(struct proxy *px) {
Willy Tarreaub625a082007-11-26 01:15:43 +01001890 if (px->lbprm.tot_weight && px->last_change < now.tv_sec) // ignore negative time
Krzysztof Oledzki85130942007-10-22 16:21:10 +02001891 return px->down_time;
1892
1893 return now.tv_sec - px->last_change + px->down_time;
1894}
Willy Tarreaubaaee002006-06-26 02:48:02 +02001895
Willy Tarreaua0cbda62007-11-01 21:39:54 +01001896/* This function parses a "balance" statement in a backend section describing
1897 * <curproxy>. It returns -1 if there is any error, otherwise zero. If it
1898 * returns -1, it may write an error message into ther <err> buffer, for at
1899 * most <errlen> bytes, trailing zero included. The trailing '\n' will not be
1900 * written. The function must be called with <args> pointing to the first word
1901 * after "balance".
1902 */
1903int backend_parse_balance(const char **args, char *err, int errlen, struct proxy *curproxy)
1904{
1905 if (!*(args[0])) {
1906 /* if no option is set, use round-robin by default */
Willy Tarreau31682232007-11-29 15:38:04 +01001907 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1908 curproxy->lbprm.algo |= BE_LB_ALGO_RR;
Willy Tarreaua0cbda62007-11-01 21:39:54 +01001909 return 0;
1910 }
1911
1912 if (!strcmp(args[0], "roundrobin")) {
Willy Tarreau31682232007-11-29 15:38:04 +01001913 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1914 curproxy->lbprm.algo |= BE_LB_ALGO_RR;
Willy Tarreaua0cbda62007-11-01 21:39:54 +01001915 }
Willy Tarreau51406232008-03-10 22:04:20 +01001916 else if (!strcmp(args[0], "leastconn")) {
1917 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1918 curproxy->lbprm.algo |= BE_LB_ALGO_LC;
1919 }
Willy Tarreaua0cbda62007-11-01 21:39:54 +01001920 else if (!strcmp(args[0], "source")) {
Willy Tarreau31682232007-11-29 15:38:04 +01001921 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1922 curproxy->lbprm.algo |= BE_LB_ALGO_SH;
Willy Tarreaua0cbda62007-11-01 21:39:54 +01001923 }
1924 else if (!strcmp(args[0], "uri")) {
Marek Majkowski9c30fc12008-04-27 23:25:55 +02001925 int arg = 1;
1926
Willy Tarreau31682232007-11-29 15:38:04 +01001927 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1928 curproxy->lbprm.algo |= BE_LB_ALGO_UH;
Marek Majkowski9c30fc12008-04-27 23:25:55 +02001929
1930 while (*args[arg]) {
1931 if (!strcmp(args[arg], "len")) {
1932 if (!*args[arg+1] || (atoi(args[arg+1]) <= 0)) {
1933 snprintf(err, errlen, "'balance uri len' expects a positive integer (got '%s').", args[arg+1]);
1934 return -1;
1935 }
1936 curproxy->uri_len_limit = atoi(args[arg+1]);
1937 arg += 2;
1938 }
1939 else if (!strcmp(args[arg], "depth")) {
1940 if (!*args[arg+1] || (atoi(args[arg+1]) <= 0)) {
1941 snprintf(err, errlen, "'balance uri depth' expects a positive integer (got '%s').", args[arg+1]);
1942 return -1;
1943 }
1944 /* hint: we store the position of the ending '/' (depth+1) so
1945 * that we avoid a comparison while computing the hash.
1946 */
1947 curproxy->uri_dirs_depth1 = atoi(args[arg+1]) + 1;
1948 arg += 2;
1949 }
1950 else {
1951 snprintf(err, errlen, "'balance uri' only accepts parameters 'len' and 'depth' (got '%s').", args[arg]);
1952 return -1;
1953 }
1954 }
Willy Tarreaua0cbda62007-11-01 21:39:54 +01001955 }
Willy Tarreau01732802007-11-01 22:48:15 +01001956 else if (!strcmp(args[0], "url_param")) {
1957 if (!*args[1]) {
1958 snprintf(err, errlen, "'balance url_param' requires an URL parameter name.");
1959 return -1;
1960 }
Willy Tarreau31682232007-11-29 15:38:04 +01001961 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1962 curproxy->lbprm.algo |= BE_LB_ALGO_PH;
Willy Tarreaua534fea2008-08-03 12:19:50 +02001963
1964 free(curproxy->url_param_name);
Willy Tarreau01732802007-11-01 22:48:15 +01001965 curproxy->url_param_name = strdup(args[1]);
Willy Tarreaua534fea2008-08-03 12:19:50 +02001966 curproxy->url_param_len = strlen(args[1]);
Marek Majkowski9c30fc12008-04-27 23:25:55 +02001967 if (*args[2]) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001968 if (strcmp(args[2], "check_post")) {
1969 snprintf(err, errlen, "'balance url_param' only accepts check_post modifier.");
1970 return -1;
1971 }
1972 if (*args[3]) {
1973 /* TODO: maybe issue a warning if there is no value, no digits or too long */
1974 curproxy->url_param_post_limit = str2ui(args[3]);
1975 }
1976 /* if no limit, or faul value in args[3], then default to a moderate wordlen */
1977 if (!curproxy->url_param_post_limit)
1978 curproxy->url_param_post_limit = 48;
1979 else if ( curproxy->url_param_post_limit < 3 )
1980 curproxy->url_param_post_limit = 3; /* minimum example: S=3 or \r\nS=6& */
1981 }
Benoitaffb4812009-03-25 13:02:10 +01001982 }
1983 else if (!strncmp(args[0], "hdr(", 4)) {
1984 const char *beg, *end;
1985
1986 beg = args[0] + 4;
1987 end = strchr(beg, ')');
1988
1989 if (!end || end == beg) {
1990 snprintf(err, errlen, "'balance hdr(name)' requires an http header field name.");
1991 return -1;
1992 }
1993
1994 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1995 curproxy->lbprm.algo |= BE_LB_ALGO_HH;
1996
1997 free(curproxy->hh_name);
1998 curproxy->hh_len = end - beg;
1999 curproxy->hh_name = my_strndup(beg, end - beg);
2000 curproxy->hh_match_domain = 0;
2001
2002 if (*args[1]) {
2003 if (strcmp(args[1], "use_domain_only")) {
2004 snprintf(err, errlen, "'balance hdr(name)' only accepts 'use_domain_only' modifier.");
2005 return -1;
2006 }
2007 curproxy->hh_match_domain = 1;
2008 }
2009
Emeric Brun736aa232009-06-30 17:56:00 +02002010 }
2011 else if (!strncmp(args[0], "rdp-cookie", 10)) {
2012 curproxy->lbprm.algo &= ~BE_LB_ALGO;
2013 curproxy->lbprm.algo |= BE_LB_ALGO_RCH;
2014
2015 if ( *(args[0] + 10 ) == '(' ) { /* cookie name */
2016 const char *beg, *end;
2017
2018 beg = args[0] + 11;
2019 end = strchr(beg, ')');
2020
2021 if (!end || end == beg) {
2022 snprintf(err, errlen, "'balance rdp-cookie(name)' requires an rdp cookie name.");
2023 return -1;
2024 }
2025
2026 free(curproxy->hh_name);
2027 curproxy->hh_name = my_strndup(beg, end - beg);
2028 curproxy->hh_len = end - beg;
2029 }
2030 else if ( *(args[0] + 10 ) == '\0' ) { /* default cookie name 'mstshash' */
2031 free(curproxy->hh_name);
2032 curproxy->hh_name = strdup("mstshash");
2033 curproxy->hh_len = strlen(curproxy->hh_name);
2034 }
2035 else { /* syntax */
2036 snprintf(err, errlen, "'balance rdp-cookie(name)' requires an rdp cookie name.");
2037 return -1;
2038 }
Willy Tarreau01732802007-11-01 22:48:15 +01002039 }
Willy Tarreaua0cbda62007-11-01 21:39:54 +01002040 else {
Emeric Brun736aa232009-06-30 17:56:00 +02002041 snprintf(err, errlen, "'balance' only supports 'roundrobin', 'leastconn', 'source', 'uri', 'url_param', 'hdr(name)' and 'rdp-cookie(name)' options.");
Willy Tarreaua0cbda62007-11-01 21:39:54 +01002042 return -1;
2043 }
2044 return 0;
2045}
2046
Willy Tarreaua9d3c1e2007-11-30 20:48:53 +01002047
2048/************************************************************************/
2049/* All supported keywords must be declared here. */
2050/************************************************************************/
2051
2052/* set test->i to the number of enabled servers on the proxy */
2053static int
2054acl_fetch_nbsrv(struct proxy *px, struct session *l4, void *l7, int dir,
2055 struct acl_expr *expr, struct acl_test *test)
2056{
2057 test->flags = ACL_TEST_F_VOL_TEST;
2058 if (expr->arg_len) {
2059 /* another proxy was designated, we must look for it */
2060 for (px = proxy; px; px = px->next)
2061 if ((px->cap & PR_CAP_BE) && !strcmp(px->id, expr->arg.str))
2062 break;
2063 }
2064 if (!px)
2065 return 0;
2066
2067 if (px->srv_act)
2068 test->i = px->srv_act;
2069 else if (px->lbprm.fbck)
2070 test->i = 1;
2071 else
2072 test->i = px->srv_bck;
2073
2074 return 1;
2075}
2076
Jeffrey 'jf' Lim5051d7b2008-09-04 01:03:03 +08002077/* set test->i to the number of enabled servers on the proxy */
2078static int
2079acl_fetch_connslots(struct proxy *px, struct session *l4, void *l7, int dir,
2080 struct acl_expr *expr, struct acl_test *test)
2081{
2082 struct server *iterator;
2083 test->flags = ACL_TEST_F_VOL_TEST;
2084 if (expr->arg_len) {
2085 /* another proxy was designated, we must look for it */
2086 for (px = proxy; px; px = px->next)
2087 if ((px->cap & PR_CAP_BE) && !strcmp(px->id, expr->arg.str))
2088 break;
2089 }
2090 if (!px)
2091 return 0;
2092
2093 test->i = 0;
2094 iterator = px->srv;
2095 while (iterator) {
2096 if ((iterator->state & 1) == 0) {
2097 iterator = iterator->next;
2098 continue;
2099 }
2100 if (iterator->maxconn == 0 || iterator->maxqueue == 0) {
2101 test->i = -1;
2102 return 1;
2103 }
2104
2105 test->i += (iterator->maxconn - iterator->cur_sess)
2106 + (iterator->maxqueue - iterator->nbpend);
2107 iterator = iterator->next;
2108 }
2109
2110 return 1;
2111}
2112
Willy Tarreau079ff0a2009-03-05 21:34:28 +01002113/* set test->i to the number of connections per second reaching the frontend */
2114static int
2115acl_fetch_fe_sess_rate(struct proxy *px, struct session *l4, void *l7, int dir,
2116 struct acl_expr *expr, struct acl_test *test)
2117{
2118 test->flags = ACL_TEST_F_VOL_TEST;
2119 if (expr->arg_len) {
2120 /* another proxy was designated, we must look for it */
2121 for (px = proxy; px; px = px->next)
2122 if ((px->cap & PR_CAP_FE) && !strcmp(px->id, expr->arg.str))
2123 break;
2124 }
2125 if (!px)
2126 return 0;
2127
2128 test->i = read_freq_ctr(&px->fe_sess_per_sec);
2129 return 1;
2130}
2131
2132/* set test->i to the number of connections per second reaching the backend */
2133static int
2134acl_fetch_be_sess_rate(struct proxy *px, struct session *l4, void *l7, int dir,
2135 struct acl_expr *expr, struct acl_test *test)
2136{
2137 test->flags = ACL_TEST_F_VOL_TEST;
2138 if (expr->arg_len) {
2139 /* another proxy was designated, we must look for it */
2140 for (px = proxy; px; px = px->next)
2141 if ((px->cap & PR_CAP_BE) && !strcmp(px->id, expr->arg.str))
2142 break;
2143 }
2144 if (!px)
2145 return 0;
2146
2147 test->i = read_freq_ctr(&px->be_sess_per_sec);
2148 return 1;
2149}
2150
Willy Tarreaua9d3c1e2007-11-30 20:48:53 +01002151
2152/* Note: must not be declared <const> as its list will be overwritten */
2153static struct acl_kw_list acl_kws = {{ },{
Jeffrey 'jf' Lim5051d7b2008-09-04 01:03:03 +08002154 { "nbsrv", acl_parse_int, acl_fetch_nbsrv, acl_match_int, ACL_USE_NOTHING },
Willy Tarreau3a8efeb2009-03-05 19:15:37 +01002155 { "connslots", acl_parse_int, acl_fetch_connslots, acl_match_int, ACL_USE_NOTHING },
Willy Tarreau079ff0a2009-03-05 21:34:28 +01002156 { "fe_sess_rate", acl_parse_int, acl_fetch_fe_sess_rate, acl_match_int, ACL_USE_NOTHING },
2157 { "be_sess_rate", acl_parse_int, acl_fetch_be_sess_rate, acl_match_int, ACL_USE_NOTHING },
Willy Tarreaua9d3c1e2007-11-30 20:48:53 +01002158 { NULL, NULL, NULL, NULL },
2159}};
2160
2161
2162__attribute__((constructor))
2163static void __backend_init(void)
2164{
2165 acl_register_keywords(&acl_kws);
2166}
2167
2168
Willy Tarreaubaaee002006-06-26 02:48:02 +02002169/*
2170 * Local variables:
2171 * c-indent-level: 8
2172 * c-basic-offset: 8
2173 * End:
2174 */