blob: 7a6b7b8f4a45c3019e04a96f8d57b32df7162540 [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>
Willy Tarreaubaaee002006-06-26 02:48:02 +020020
Willy Tarreau2dd0d472006-06-29 17:53:05 +020021#include <common/compat.h>
Willy Tarreaue3ba5f02006-06-29 18:54:54 +020022#include <common/config.h>
Willy Tarreau7c669d72008-06-20 15:04:11 +020023#include <common/debug.h>
Willy Tarreaub625a082007-11-26 01:15:43 +010024#include <common/eb32tree.h>
Willy Tarreau0c303ee2008-07-07 00:09:58 +020025#include <common/ticks.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020026#include <common/time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020027
Willy Tarreaubaaee002006-06-26 02:48:02 +020028#include <types/global.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020029
Willy Tarreaua9d3c1e2007-11-30 20:48:53 +010030#include <proto/acl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020031#include <proto/backend.h>
Willy Tarreau14c8aac2007-05-08 19:46:30 +020032#include <proto/client.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020033#include <proto/proto_http.h>
Willy Tarreaue8c66af2008-01-13 18:40:14 +010034#include <proto/proto_tcp.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020035#include <proto/queue.h>
Willy Tarreau7f062c42009-03-05 18:43:00 +010036#include <proto/server.h>
Willy Tarreau7c669d72008-06-20 15:04:11 +020037#include <proto/session.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020038#include <proto/task.h>
39
Willy Tarreaub625a082007-11-26 01:15:43 +010040static inline void fwrr_remove_from_tree(struct server *s);
41static inline void fwrr_queue_by_weight(struct eb_root *root, struct server *s);
42static inline void fwrr_dequeue_srv(struct server *s);
43static void fwrr_get_srv(struct server *s);
44static void fwrr_queue_srv(struct server *s);
45
46/* This function returns non-zero if a server with the given weight and state
47 * is usable for LB, otherwise zero.
48 */
49static inline int srv_is_usable(int state, int weight)
50{
51 if (!weight)
52 return 0;
Willy Tarreau48494c02007-11-30 10:41:39 +010053 if (state & SRV_GOINGDOWN)
54 return 0;
Willy Tarreaub625a082007-11-26 01:15:43 +010055 if (!(state & SRV_RUNNING))
56 return 0;
57 return 1;
58}
59
Willy Tarreaubaaee002006-06-26 02:48:02 +020060/*
61 * This function recounts the number of usable active and backup servers for
62 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
Willy Tarreaub625a082007-11-26 01:15:43 +010063 * This function also recomputes the total active and backup weights. However,
Willy Tarreauf4cca452008-03-08 21:42:54 +010064 * it does not update tot_weight nor tot_used. Use update_backend_weight() for
Willy Tarreaub625a082007-11-26 01:15:43 +010065 * this.
Willy Tarreaubaaee002006-06-26 02:48:02 +020066 */
Willy Tarreaub625a082007-11-26 01:15:43 +010067static void recount_servers(struct proxy *px)
Willy Tarreaubaaee002006-06-26 02:48:02 +020068{
69 struct server *srv;
70
Willy Tarreau20697042007-11-15 23:26:18 +010071 px->srv_act = px->srv_bck = 0;
72 px->lbprm.tot_wact = px->lbprm.tot_wbck = 0;
Willy Tarreaub625a082007-11-26 01:15:43 +010073 px->lbprm.fbck = NULL;
Willy Tarreaubaaee002006-06-26 02:48:02 +020074 for (srv = px->srv; srv != NULL; srv = srv->next) {
Willy Tarreaub625a082007-11-26 01:15:43 +010075 if (!srv_is_usable(srv->state, srv->eweight))
76 continue;
77
78 if (srv->state & SRV_BACKUP) {
79 if (!px->srv_bck &&
Willy Tarreauf4cca452008-03-08 21:42:54 +010080 !(px->options & PR_O_USE_ALL_BK))
Willy Tarreaub625a082007-11-26 01:15:43 +010081 px->lbprm.fbck = srv;
82 px->srv_bck++;
83 px->lbprm.tot_wbck += srv->eweight;
84 } else {
85 px->srv_act++;
86 px->lbprm.tot_wact += srv->eweight;
Willy Tarreaubaaee002006-06-26 02:48:02 +020087 }
88 }
Willy Tarreaub625a082007-11-26 01:15:43 +010089}
Willy Tarreau20697042007-11-15 23:26:18 +010090
Willy Tarreaub625a082007-11-26 01:15:43 +010091/* This function simply updates the backend's tot_weight and tot_used values
92 * after servers weights have been updated. It is designed to be used after
93 * recount_servers() or equivalent.
94 */
95static void update_backend_weight(struct proxy *px)
96{
Willy Tarreau20697042007-11-15 23:26:18 +010097 if (px->srv_act) {
98 px->lbprm.tot_weight = px->lbprm.tot_wact;
99 px->lbprm.tot_used = px->srv_act;
100 }
Willy Tarreaub625a082007-11-26 01:15:43 +0100101 else if (px->lbprm.fbck) {
102 /* use only the first backup server */
103 px->lbprm.tot_weight = px->lbprm.fbck->eweight;
104 px->lbprm.tot_used = 1;
Willy Tarreau20697042007-11-15 23:26:18 +0100105 }
106 else {
Willy Tarreaub625a082007-11-26 01:15:43 +0100107 px->lbprm.tot_weight = px->lbprm.tot_wbck;
108 px->lbprm.tot_used = px->srv_bck;
Willy Tarreau20697042007-11-15 23:26:18 +0100109 }
Willy Tarreaub625a082007-11-26 01:15:43 +0100110}
111
112/* this function updates the map according to server <srv>'s new state */
113static void map_set_server_status_down(struct server *srv)
114{
115 struct proxy *p = srv->proxy;
116
117 if (srv->state == srv->prev_state &&
118 srv->eweight == srv->prev_eweight)
119 return;
120
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100121 if (srv_is_usable(srv->state, srv->eweight))
122 goto out_update_state;
123
Willy Tarreaub625a082007-11-26 01:15:43 +0100124 /* FIXME: could be optimized since we know what changed */
125 recount_servers(p);
126 update_backend_weight(p);
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100127 p->lbprm.map.state |= PR_MAP_RECALC;
128 out_update_state:
Willy Tarreaub625a082007-11-26 01:15:43 +0100129 srv->prev_state = srv->state;
130 srv->prev_eweight = srv->eweight;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200131}
132
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100133/* This function updates the map according to server <srv>'s new state */
Willy Tarreaub625a082007-11-26 01:15:43 +0100134static void map_set_server_status_up(struct server *srv)
135{
136 struct proxy *p = srv->proxy;
137
138 if (srv->state == srv->prev_state &&
139 srv->eweight == srv->prev_eweight)
140 return;
141
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100142 if (!srv_is_usable(srv->state, srv->eweight))
143 goto out_update_state;
144
Willy Tarreaub625a082007-11-26 01:15:43 +0100145 /* FIXME: could be optimized since we know what changed */
146 recount_servers(p);
147 update_backend_weight(p);
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100148 p->lbprm.map.state |= PR_MAP_RECALC;
149 out_update_state:
Willy Tarreaub625a082007-11-26 01:15:43 +0100150 srv->prev_state = srv->state;
151 srv->prev_eweight = srv->eweight;
Willy Tarreaub625a082007-11-26 01:15:43 +0100152}
153
Willy Tarreau20697042007-11-15 23:26:18 +0100154/* This function recomputes the server map for proxy px. It relies on
155 * px->lbprm.tot_wact, tot_wbck, tot_used, tot_weight, so it must be
156 * called after recount_servers(). It also expects px->lbprm.map.srv
157 * to be allocated with the largest size needed. It updates tot_weight.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200158 */
159void recalc_server_map(struct proxy *px)
160{
161 int o, tot, flag;
162 struct server *cur, *best;
163
Willy Tarreau20697042007-11-15 23:26:18 +0100164 switch (px->lbprm.tot_used) {
165 case 0: /* no server */
166 px->lbprm.map.state &= ~PR_MAP_RECALC;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200167 return;
Willy Tarreau20697042007-11-15 23:26:18 +0100168 case 1: /* only one server, just fill first entry */
169 tot = 1;
170 break;
171 default:
172 tot = px->lbprm.tot_weight;
173 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200174 }
175
Willy Tarreau20697042007-11-15 23:26:18 +0100176 /* here we *know* that we have some servers */
177 if (px->srv_act)
178 flag = SRV_RUNNING;
179 else
180 flag = SRV_RUNNING | SRV_BACKUP;
181
Willy Tarreaubaaee002006-06-26 02:48:02 +0200182 /* this algorithm gives priority to the first server, which means that
183 * it will respect the declaration order for equivalent weights, and
184 * that whatever the weights, the first server called will always be
Willy Tarreau20697042007-11-15 23:26:18 +0100185 * the first declared. This is an important asumption for the backup
Willy Tarreaubaaee002006-06-26 02:48:02 +0200186 * case, where we want the first server only.
187 */
188 for (cur = px->srv; cur; cur = cur->next)
189 cur->wscore = 0;
190
191 for (o = 0; o < tot; o++) {
192 int max = 0;
193 best = NULL;
194 for (cur = px->srv; cur; cur = cur->next) {
Willy Tarreau6704d672009-06-15 10:56:05 +0200195 if (cur->eweight &&
196 flag == (cur->state &
Willy Tarreau48494c02007-11-30 10:41:39 +0100197 (SRV_RUNNING | SRV_GOINGDOWN | SRV_BACKUP))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200198 int v;
199
200 /* If we are forced to return only one server, we don't want to
201 * go further, because we would return the wrong one due to
202 * divide overflow.
203 */
204 if (tot == 1) {
205 best = cur;
Willy Tarreau20697042007-11-15 23:26:18 +0100206 /* note that best->wscore will be wrong but we don't care */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200207 break;
208 }
209
Willy Tarreau417fae02007-03-25 21:16:40 +0200210 cur->wscore += cur->eweight;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200211 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
212 if (best == NULL || v > max) {
213 max = v;
214 best = cur;
215 }
216 }
217 }
Willy Tarreau20697042007-11-15 23:26:18 +0100218 px->lbprm.map.srv[o] = best;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200219 best->wscore -= tot;
220 }
Willy Tarreau20697042007-11-15 23:26:18 +0100221 px->lbprm.map.state &= ~PR_MAP_RECALC;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200222}
223
Willy Tarreau5dc2fa62007-11-19 19:10:18 +0100224/* This function is responsible of building the server MAP for map-based LB
225 * algorithms, allocating the map, and setting p->lbprm.wmult to the GCD of the
226 * weights if applicable. It should be called only once per proxy, at config
227 * time.
228 */
229void init_server_map(struct proxy *p)
230{
231 struct server *srv;
232 int pgcd;
233 int act, bck;
234
Willy Tarreaub625a082007-11-26 01:15:43 +0100235 p->lbprm.set_server_status_up = map_set_server_status_up;
236 p->lbprm.set_server_status_down = map_set_server_status_down;
237 p->lbprm.update_server_eweight = NULL;
238
Willy Tarreau5dc2fa62007-11-19 19:10:18 +0100239 if (!p->srv)
240 return;
241
242 /* We will factor the weights to reduce the table,
Willy Tarreau6704d672009-06-15 10:56:05 +0200243 * using Euclide's largest common divisor algorithm.
244 * Since we may have zero weights, we have to first
245 * find a non-zero weight server.
Willy Tarreau5dc2fa62007-11-19 19:10:18 +0100246 */
Willy Tarreau6704d672009-06-15 10:56:05 +0200247 pgcd = 1;
248 srv = p->srv;
249 while (srv && !srv->uweight)
250 srv = srv->next;
251
252 if (srv) {
253 pgcd = srv->uweight; /* note: cannot be zero */
254 while (pgcd > 1 && (srv = srv->next)) {
255 int w = srv->uweight;
256 while (w) {
257 int t = pgcd % w;
258 pgcd = w;
259 w = t;
260 }
Willy Tarreau5dc2fa62007-11-19 19:10:18 +0100261 }
262 }
263
264 /* It is sometimes useful to know what factor to apply
265 * to the backend's effective weight to know its real
266 * weight.
267 */
268 p->lbprm.wmult = pgcd;
269
270 act = bck = 0;
271 for (srv = p->srv; srv; srv = srv->next) {
272 srv->eweight = srv->uweight / pgcd;
Willy Tarreaub625a082007-11-26 01:15:43 +0100273 srv->prev_eweight = srv->eweight;
274 srv->prev_state = srv->state;
Willy Tarreau5dc2fa62007-11-19 19:10:18 +0100275 if (srv->state & SRV_BACKUP)
276 bck += srv->eweight;
277 else
278 act += srv->eweight;
279 }
280
281 /* this is the largest map we will ever need for this servers list */
282 if (act < bck)
283 act = bck;
284
Willy Tarreau6704d672009-06-15 10:56:05 +0200285 if (!act)
286 act = 1;
287
Willy Tarreau5dc2fa62007-11-19 19:10:18 +0100288 p->lbprm.map.srv = (struct server **)calloc(act, sizeof(struct server *));
289 /* recounts servers and their weights */
290 p->lbprm.map.state = PR_MAP_RECALC;
291 recount_servers(p);
Willy Tarreaub625a082007-11-26 01:15:43 +0100292 update_backend_weight(p);
Willy Tarreau5dc2fa62007-11-19 19:10:18 +0100293 recalc_server_map(p);
294}
295
Willy Tarreaub625a082007-11-26 01:15:43 +0100296/* This function updates the server trees according to server <srv>'s new
297 * state. It should be called when server <srv>'s status changes to down.
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100298 * It is not important whether the server was already down or not. It is not
299 * important either that the new state is completely down (the caller may not
300 * know all the variables of a server's state).
Willy Tarreaub625a082007-11-26 01:15:43 +0100301 */
302static void fwrr_set_server_status_down(struct server *srv)
303{
304 struct proxy *p = srv->proxy;
305 struct fwrr_group *grp;
306
307 if (srv->state == srv->prev_state &&
308 srv->eweight == srv->prev_eweight)
309 return;
310
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100311 if (srv_is_usable(srv->state, srv->eweight))
312 goto out_update_state;
313
Willy Tarreaub625a082007-11-26 01:15:43 +0100314 if (!srv_is_usable(srv->prev_state, srv->prev_eweight))
315 /* server was already down */
316 goto out_update_backend;
317
318 grp = (srv->state & SRV_BACKUP) ? &p->lbprm.fwrr.bck : &p->lbprm.fwrr.act;
319 grp->next_weight -= srv->prev_eweight;
320
321 if (srv->state & SRV_BACKUP) {
322 p->lbprm.tot_wbck = p->lbprm.fwrr.bck.next_weight;
323 p->srv_bck--;
324
325 if (srv == p->lbprm.fbck) {
326 /* we lost the first backup server in a single-backup
327 * configuration, we must search another one.
328 */
329 struct server *srv2 = p->lbprm.fbck;
330 do {
331 srv2 = srv2->next;
332 } while (srv2 &&
333 !((srv2->state & SRV_BACKUP) &&
334 srv_is_usable(srv2->state, srv2->eweight)));
335 p->lbprm.fbck = srv2;
336 }
337 } else {
338 p->lbprm.tot_wact = p->lbprm.fwrr.act.next_weight;
339 p->srv_act--;
340 }
341
342 fwrr_dequeue_srv(srv);
343 fwrr_remove_from_tree(srv);
344
345out_update_backend:
346 /* check/update tot_used, tot_weight */
347 update_backend_weight(p);
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100348 out_update_state:
Willy Tarreaub625a082007-11-26 01:15:43 +0100349 srv->prev_state = srv->state;
350 srv->prev_eweight = srv->eweight;
Willy Tarreaub625a082007-11-26 01:15:43 +0100351}
352
353/* This function updates the server trees according to server <srv>'s new
354 * state. It should be called when server <srv>'s status changes to up.
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100355 * It is not important whether the server was already down or not. It is not
356 * important either that the new state is completely UP (the caller may not
357 * know all the variables of a server's state). This function will not change
Willy Tarreaub625a082007-11-26 01:15:43 +0100358 * the weight of a server which was already up.
359 */
360static void fwrr_set_server_status_up(struct server *srv)
361{
362 struct proxy *p = srv->proxy;
363 struct fwrr_group *grp;
364
365 if (srv->state == srv->prev_state &&
366 srv->eweight == srv->prev_eweight)
367 return;
368
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100369 if (!srv_is_usable(srv->state, srv->eweight))
370 goto out_update_state;
371
Willy Tarreaub625a082007-11-26 01:15:43 +0100372 if (srv_is_usable(srv->prev_state, srv->prev_eweight))
373 /* server was already up */
374 goto out_update_backend;
375
376 grp = (srv->state & SRV_BACKUP) ? &p->lbprm.fwrr.bck : &p->lbprm.fwrr.act;
377 grp->next_weight += srv->eweight;
378
379 if (srv->state & SRV_BACKUP) {
380 p->lbprm.tot_wbck = p->lbprm.fwrr.bck.next_weight;
381 p->srv_bck++;
382
Willy Tarreauf4cca452008-03-08 21:42:54 +0100383 if (!(p->options & PR_O_USE_ALL_BK)) {
384 if (!p->lbprm.fbck) {
385 /* there was no backup server anymore */
Willy Tarreaub625a082007-11-26 01:15:43 +0100386 p->lbprm.fbck = srv;
Willy Tarreauf4cca452008-03-08 21:42:54 +0100387 } else {
388 /* we may have restored a backup server prior to fbck,
389 * in which case it should replace it.
390 */
391 struct server *srv2 = srv;
392 do {
393 srv2 = srv2->next;
394 } while (srv2 && (srv2 != p->lbprm.fbck));
395 if (srv2)
396 p->lbprm.fbck = srv;
397 }
Willy Tarreaub625a082007-11-26 01:15:43 +0100398 }
399 } else {
400 p->lbprm.tot_wact = p->lbprm.fwrr.act.next_weight;
401 p->srv_act++;
402 }
403
404 /* note that eweight cannot be 0 here */
405 fwrr_get_srv(srv);
406 srv->npos = grp->curr_pos + (grp->next_weight + grp->curr_weight - grp->curr_pos) / srv->eweight;
407 fwrr_queue_srv(srv);
408
409out_update_backend:
410 /* check/update tot_used, tot_weight */
411 update_backend_weight(p);
Willy Tarreau0ebe1062007-11-30 11:11:02 +0100412 out_update_state:
Willy Tarreaub625a082007-11-26 01:15:43 +0100413 srv->prev_state = srv->state;
414 srv->prev_eweight = srv->eweight;
415}
416
417/* This function must be called after an update to server <srv>'s effective
418 * weight. It may be called after a state change too.
419 */
420static void fwrr_update_server_weight(struct server *srv)
421{
422 int old_state, new_state;
423 struct proxy *p = srv->proxy;
424 struct fwrr_group *grp;
425
426 if (srv->state == srv->prev_state &&
427 srv->eweight == srv->prev_eweight)
428 return;
429
430 /* If changing the server's weight changes its state, we simply apply
431 * the procedures we already have for status change. If the state
432 * remains down, the server is not in any tree, so it's as easy as
433 * updating its values. If the state remains up with different weights,
434 * there are some computations to perform to find a new place and
435 * possibly a new tree for this server.
436 */
437
438 old_state = srv_is_usable(srv->prev_state, srv->prev_eweight);
439 new_state = srv_is_usable(srv->state, srv->eweight);
440
441 if (!old_state && !new_state) {
442 srv->prev_state = srv->state;
443 srv->prev_eweight = srv->eweight;
444 return;
445 }
446 else if (!old_state && new_state) {
447 fwrr_set_server_status_up(srv);
448 return;
449 }
450 else if (old_state && !new_state) {
451 fwrr_set_server_status_down(srv);
452 return;
453 }
454
455 grp = (srv->state & SRV_BACKUP) ? &p->lbprm.fwrr.bck : &p->lbprm.fwrr.act;
456 grp->next_weight = grp->next_weight - srv->prev_eweight + srv->eweight;
457
458 p->lbprm.tot_wact = p->lbprm.fwrr.act.next_weight;
459 p->lbprm.tot_wbck = p->lbprm.fwrr.bck.next_weight;
460
461 if (srv->lb_tree == grp->init) {
462 fwrr_dequeue_srv(srv);
463 fwrr_queue_by_weight(grp->init, srv);
464 }
465 else if (!srv->lb_tree) {
466 /* FIXME: server was down. This is not possible right now but
467 * may be needed soon for slowstart or graceful shutdown.
468 */
469 fwrr_dequeue_srv(srv);
470 fwrr_get_srv(srv);
471 srv->npos = grp->curr_pos + (grp->next_weight + grp->curr_weight - grp->curr_pos) / srv->eweight;
472 fwrr_queue_srv(srv);
473 } else {
474 /* The server is either active or in the next queue. If it's
475 * still in the active queue and it has not consumed all of its
476 * places, let's adjust its next position.
477 */
478 fwrr_get_srv(srv);
479
480 if (srv->eweight > 0) {
481 int prev_next = srv->npos;
482 int step = grp->next_weight / srv->eweight;
483
484 srv->npos = srv->lpos + step;
485 srv->rweight = 0;
486
487 if (srv->npos > prev_next)
488 srv->npos = prev_next;
489 if (srv->npos < grp->curr_pos + 2)
490 srv->npos = grp->curr_pos + step;
491 } else {
492 /* push it into the next tree */
493 srv->npos = grp->curr_pos + grp->curr_weight;
494 }
495
496 fwrr_dequeue_srv(srv);
497 fwrr_queue_srv(srv);
498 }
499
500 update_backend_weight(p);
501 srv->prev_state = srv->state;
502 srv->prev_eweight = srv->eweight;
503}
504
505/* Remove a server from a tree. It must have previously been dequeued. This
506 * function is meant to be called when a server is going down or has its
507 * weight disabled.
508 */
509static inline void fwrr_remove_from_tree(struct server *s)
510{
511 s->lb_tree = NULL;
512}
513
514/* Queue a server in the weight tree <root>, assuming the weight is >0.
515 * We want to sort them by inverted weights, because we need to place
516 * heavy servers first in order to get a smooth distribution.
517 */
518static inline void fwrr_queue_by_weight(struct eb_root *root, struct server *s)
519{
Willy Tarreaub698f0f2007-12-02 11:01:23 +0100520 s->lb_node.key = SRV_EWGHT_MAX - s->eweight;
Willy Tarreaub625a082007-11-26 01:15:43 +0100521 eb32_insert(root, &s->lb_node);
522 s->lb_tree = root;
523}
524
525/* This function is responsible for building the weight trees in case of fast
526 * weighted round-robin. It also sets p->lbprm.wdiv to the eweight to uweight
527 * ratio. Both active and backup groups are initialized.
528 */
529void fwrr_init_server_groups(struct proxy *p)
530{
531 struct server *srv;
532 struct eb_root init_head = EB_ROOT;
533
534 p->lbprm.set_server_status_up = fwrr_set_server_status_up;
535 p->lbprm.set_server_status_down = fwrr_set_server_status_down;
536 p->lbprm.update_server_eweight = fwrr_update_server_weight;
537
538 p->lbprm.wdiv = BE_WEIGHT_SCALE;
539 for (srv = p->srv; srv; srv = srv->next) {
540 srv->prev_eweight = srv->eweight = srv->uweight * BE_WEIGHT_SCALE;
541 srv->prev_state = srv->state;
542 }
543
544 recount_servers(p);
545 update_backend_weight(p);
546
547 /* prepare the active servers group */
548 p->lbprm.fwrr.act.curr_pos = p->lbprm.fwrr.act.curr_weight =
549 p->lbprm.fwrr.act.next_weight = p->lbprm.tot_wact;
550 p->lbprm.fwrr.act.curr = p->lbprm.fwrr.act.t0 =
551 p->lbprm.fwrr.act.t1 = init_head;
552 p->lbprm.fwrr.act.init = &p->lbprm.fwrr.act.t0;
553 p->lbprm.fwrr.act.next = &p->lbprm.fwrr.act.t1;
554
555 /* prepare the backup servers group */
556 p->lbprm.fwrr.bck.curr_pos = p->lbprm.fwrr.bck.curr_weight =
557 p->lbprm.fwrr.bck.next_weight = p->lbprm.tot_wbck;
558 p->lbprm.fwrr.bck.curr = p->lbprm.fwrr.bck.t0 =
559 p->lbprm.fwrr.bck.t1 = init_head;
560 p->lbprm.fwrr.bck.init = &p->lbprm.fwrr.bck.t0;
561 p->lbprm.fwrr.bck.next = &p->lbprm.fwrr.bck.t1;
562
563 /* queue active and backup servers in two distinct groups */
564 for (srv = p->srv; srv; srv = srv->next) {
565 if (!srv_is_usable(srv->state, srv->eweight))
566 continue;
567 fwrr_queue_by_weight((srv->state & SRV_BACKUP) ?
568 p->lbprm.fwrr.bck.init :
569 p->lbprm.fwrr.act.init,
570 srv);
571 }
572}
573
574/* simply removes a server from a weight tree */
575static inline void fwrr_dequeue_srv(struct server *s)
576{
577 eb32_delete(&s->lb_node);
578}
579
580/* queues a server into the appropriate group and tree depending on its
581 * backup status, and ->npos. If the server is disabled, simply assign
582 * it to the NULL tree.
583 */
584static void fwrr_queue_srv(struct server *s)
585{
586 struct proxy *p = s->proxy;
587 struct fwrr_group *grp;
588
589 grp = (s->state & SRV_BACKUP) ? &p->lbprm.fwrr.bck : &p->lbprm.fwrr.act;
590
591 /* Delay everything which does not fit into the window and everything
592 * which does not fit into the theorical new window.
593 */
594 if (!srv_is_usable(s->state, s->eweight)) {
595 fwrr_remove_from_tree(s);
596 }
597 else if (s->eweight <= 0 ||
598 s->npos >= 2 * grp->curr_weight ||
599 s->npos >= grp->curr_weight + grp->next_weight) {
600 /* put into next tree, and readjust npos in case we could
601 * finally take this back to current. */
602 s->npos -= grp->curr_weight;
603 fwrr_queue_by_weight(grp->next, s);
604 }
605 else {
Willy Tarreaub698f0f2007-12-02 11:01:23 +0100606 /* The sorting key is stored in units of s->npos * user_weight
607 * in order to avoid overflows. As stated in backend.h, the
608 * lower the scale, the rougher the weights modulation, and the
609 * higher the scale, the lower the number of servers without
610 * overflow. With this formula, the result is always positive,
611 * so we can use eb3é_insert().
Willy Tarreaub625a082007-11-26 01:15:43 +0100612 */
Willy Tarreaub698f0f2007-12-02 11:01:23 +0100613 s->lb_node.key = SRV_UWGHT_RANGE * s->npos +
614 (unsigned)(SRV_EWGHT_MAX + s->rweight - s->eweight) / BE_WEIGHT_SCALE;
615
616 eb32_insert(&grp->curr, &s->lb_node);
Willy Tarreaub625a082007-11-26 01:15:43 +0100617 s->lb_tree = &grp->curr;
618 }
619}
620
621/* prepares a server when extracting it from the "init" tree */
622static inline void fwrr_get_srv_init(struct server *s)
623{
624 s->npos = s->rweight = 0;
625}
626
627/* prepares a server when extracting it from the "next" tree */
628static inline void fwrr_get_srv_next(struct server *s)
629{
630 struct fwrr_group *grp = (s->state & SRV_BACKUP) ?
631 &s->proxy->lbprm.fwrr.bck :
632 &s->proxy->lbprm.fwrr.act;
633
634 s->npos += grp->curr_weight;
635}
636
637/* prepares a server when it was marked down */
638static inline void fwrr_get_srv_down(struct server *s)
639{
640 struct fwrr_group *grp = (s->state & SRV_BACKUP) ?
641 &s->proxy->lbprm.fwrr.bck :
642 &s->proxy->lbprm.fwrr.act;
643
644 s->npos = grp->curr_pos;
645}
646
647/* prepares a server when extracting it from its tree */
648static void fwrr_get_srv(struct server *s)
649{
650 struct proxy *p = s->proxy;
651 struct fwrr_group *grp = (s->state & SRV_BACKUP) ?
652 &p->lbprm.fwrr.bck :
653 &p->lbprm.fwrr.act;
654
655 if (s->lb_tree == grp->init) {
656 fwrr_get_srv_init(s);
657 }
658 else if (s->lb_tree == grp->next) {
659 fwrr_get_srv_next(s);
660 }
661 else if (s->lb_tree == NULL) {
662 fwrr_get_srv_down(s);
663 }
664}
665
666/* switches trees "init" and "next" for FWRR group <grp>. "init" should be empty
667 * when this happens, and "next" filled with servers sorted by weights.
668 */
669static inline void fwrr_switch_trees(struct fwrr_group *grp)
670{
671 struct eb_root *swap;
672 swap = grp->init;
673 grp->init = grp->next;
674 grp->next = swap;
675 grp->curr_weight = grp->next_weight;
676 grp->curr_pos = grp->curr_weight;
677}
678
679/* return next server from the current tree in FWRR group <grp>, or a server
680 * from the "init" tree if appropriate. If both trees are empty, return NULL.
681 */
682static struct server *fwrr_get_server_from_group(struct fwrr_group *grp)
683{
684 struct eb32_node *node;
685 struct server *s;
686
687 node = eb32_first(&grp->curr);
688 s = eb32_entry(node, struct server, lb_node);
689
690 if (!node || s->npos > grp->curr_pos) {
691 /* either we have no server left, or we have a hole */
692 struct eb32_node *node2;
693 node2 = eb32_first(grp->init);
694 if (node2) {
695 node = node2;
696 s = eb32_entry(node, struct server, lb_node);
697 fwrr_get_srv_init(s);
698 if (s->eweight == 0) /* FIXME: is it possible at all ? */
699 node = NULL;
700 }
701 }
702 if (node)
703 return s;
704 else
705 return NULL;
706}
707
708/* Computes next position of server <s> in the group. It is mandatory for <s>
709 * to have a non-zero, positive eweight.
710*/
711static inline void fwrr_update_position(struct fwrr_group *grp, struct server *s)
712{
713 if (!s->npos) {
714 /* first time ever for this server */
715 s->lpos = grp->curr_pos;
716 s->npos = grp->curr_pos + grp->next_weight / s->eweight;
717 s->rweight += grp->next_weight % s->eweight;
718
719 if (s->rweight >= s->eweight) {
720 s->rweight -= s->eweight;
721 s->npos++;
722 }
723 } else {
724 s->lpos = s->npos;
725 s->npos += grp->next_weight / s->eweight;
726 s->rweight += grp->next_weight % s->eweight;
727
728 if (s->rweight >= s->eweight) {
729 s->rweight -= s->eweight;
730 s->npos++;
731 }
732 }
733}
734
735/* Return next server from the current tree in backend <p>, or a server from
736 * the init tree if appropriate. If both trees are empty, return NULL.
737 * Saturated servers are skipped and requeued.
738 */
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100739static struct server *fwrr_get_next_server(struct proxy *p, struct server *srvtoavoid)
Willy Tarreaub625a082007-11-26 01:15:43 +0100740{
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100741 struct server *srv, *full, *avoided;
Willy Tarreaub625a082007-11-26 01:15:43 +0100742 struct fwrr_group *grp;
Willy Tarreaub625a082007-11-26 01:15:43 +0100743 int switched;
744
745 if (p->srv_act)
746 grp = &p->lbprm.fwrr.act;
747 else if (p->lbprm.fbck)
748 return p->lbprm.fbck;
749 else if (p->srv_bck)
750 grp = &p->lbprm.fwrr.bck;
751 else
752 return NULL;
753
754 switched = 0;
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100755 avoided = NULL;
Willy Tarreaub625a082007-11-26 01:15:43 +0100756 full = NULL; /* NULL-terminated list of saturated servers */
757 while (1) {
758 /* if we see an empty group, let's first try to collect weights
759 * which might have recently changed.
760 */
761 if (!grp->curr_weight)
762 grp->curr_pos = grp->curr_weight = grp->next_weight;
763
764 /* get first server from the "current" tree. When the end of
765 * the tree is reached, we may have to switch, but only once.
766 */
767 while (1) {
768 srv = fwrr_get_server_from_group(grp);
769 if (srv)
770 break;
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100771 if (switched) {
772 if (avoided) {
773 srv = avoided;
774 break;
775 }
Willy Tarreaub625a082007-11-26 01:15:43 +0100776 goto requeue_servers;
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100777 }
Willy Tarreaub625a082007-11-26 01:15:43 +0100778 switched = 1;
779 fwrr_switch_trees(grp);
780
781 }
782
783 /* OK, we have a server. However, it may be saturated, in which
784 * case we don't want to reconsider it for now. We'll update
785 * its position and dequeue it anyway, so that we can move it
786 * to a better place afterwards.
787 */
788 fwrr_update_position(grp, srv);
789 fwrr_dequeue_srv(srv);
790 grp->curr_pos++;
Willy Tarreau7c669d72008-06-20 15:04:11 +0200791 if (!srv->maxconn || (!srv->nbpend && srv->served < srv_dynamic_maxconn(srv))) {
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100792 /* make sure it is not the server we are trying to exclude... */
793 if (srv != srvtoavoid || avoided)
794 break;
795
796 avoided = srv; /* ...but remember that is was selected yet avoided */
797 }
Willy Tarreaub625a082007-11-26 01:15:43 +0100798
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100799 /* the server is saturated or avoided, let's chain it for later reinsertion */
Willy Tarreaub625a082007-11-26 01:15:43 +0100800 srv->next_full = full;
801 full = srv;
802 }
803
804 /* OK, we got the best server, let's update it */
805 fwrr_queue_srv(srv);
806
807 requeue_servers:
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100808 /* Requeue all extracted servers. If full==srv then it was
809 * avoided (unsucessfully) and chained, omit it now.
810 */
Willy Tarreau70bcfb72008-01-27 02:21:53 +0100811 if (unlikely(full != NULL)) {
Willy Tarreaub625a082007-11-26 01:15:43 +0100812 if (switched) {
813 /* the tree has switched, requeue all extracted servers
814 * into "init", because their place was lost, and only
815 * their weight matters.
816 */
817 do {
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100818 if (likely(full != srv))
819 fwrr_queue_by_weight(grp->init, full);
Willy Tarreaub625a082007-11-26 01:15:43 +0100820 full = full->next_full;
821 } while (full);
822 } else {
823 /* requeue all extracted servers just as if they were consumed
824 * so that they regain their expected place.
825 */
826 do {
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +0100827 if (likely(full != srv))
828 fwrr_queue_srv(full);
Willy Tarreaub625a082007-11-26 01:15:43 +0100829 full = full->next_full;
830 } while (full);
831 }
832 }
833 return srv;
834}
835
Willy Tarreau51406232008-03-10 22:04:20 +0100836/* Remove a server from a tree. It must have previously been dequeued. This
837 * function is meant to be called when a server is going down or has its
838 * weight disabled.
839 */
840static inline void fwlc_remove_from_tree(struct server *s)
841{
842 s->lb_tree = NULL;
843}
844
845/* simply removes a server from a tree */
846static inline void fwlc_dequeue_srv(struct server *s)
847{
848 eb32_delete(&s->lb_node);
849}
850
851/* Queue a server in its associated tree, assuming the weight is >0.
852 * Servers are sorted by #conns/weight. To ensure maximum accuracy,
853 * we use #conns*SRV_EWGHT_MAX/eweight as the sorting key.
854 */
855static inline void fwlc_queue_srv(struct server *s)
856{
Willy Tarreau7c669d72008-06-20 15:04:11 +0200857 s->lb_node.key = s->served * SRV_EWGHT_MAX / s->eweight;
Willy Tarreau51406232008-03-10 22:04:20 +0100858 eb32_insert(s->lb_tree, &s->lb_node);
859}
860
861/* Re-position the server in the FWLC tree after it has been assigned one
862 * connection or after it has released one. Note that it is possible that
863 * the server has been moved out of the tree due to failed health-checks.
864 */
865static void fwlc_srv_reposition(struct server *s)
866{
867 if (!s->lb_tree)
868 return;
869 fwlc_dequeue_srv(s);
870 fwlc_queue_srv(s);
871}
872
873/* This function updates the server trees according to server <srv>'s new
874 * state. It should be called when server <srv>'s status changes to down.
875 * It is not important whether the server was already down or not. It is not
876 * important either that the new state is completely down (the caller may not
877 * know all the variables of a server's state).
878 */
879static void fwlc_set_server_status_down(struct server *srv)
880{
881 struct proxy *p = srv->proxy;
882
883 if (srv->state == srv->prev_state &&
884 srv->eweight == srv->prev_eweight)
885 return;
886
887 if (srv_is_usable(srv->state, srv->eweight))
888 goto out_update_state;
889
890 if (!srv_is_usable(srv->prev_state, srv->prev_eweight))
891 /* server was already down */
892 goto out_update_backend;
893
894 if (srv->state & SRV_BACKUP) {
895 p->lbprm.tot_wbck -= srv->prev_eweight;
896 p->srv_bck--;
897
898 if (srv == p->lbprm.fbck) {
899 /* we lost the first backup server in a single-backup
900 * configuration, we must search another one.
901 */
902 struct server *srv2 = p->lbprm.fbck;
903 do {
904 srv2 = srv2->next;
905 } while (srv2 &&
906 !((srv2->state & SRV_BACKUP) &&
907 srv_is_usable(srv2->state, srv2->eweight)));
908 p->lbprm.fbck = srv2;
909 }
910 } else {
911 p->lbprm.tot_wact -= srv->prev_eweight;
912 p->srv_act--;
913 }
914
915 fwlc_dequeue_srv(srv);
916 fwlc_remove_from_tree(srv);
917
918out_update_backend:
919 /* check/update tot_used, tot_weight */
920 update_backend_weight(p);
921 out_update_state:
922 srv->prev_state = srv->state;
923 srv->prev_eweight = srv->eweight;
924}
925
926/* This function updates the server trees according to server <srv>'s new
927 * state. It should be called when server <srv>'s status changes to up.
928 * It is not important whether the server was already down or not. It is not
929 * important either that the new state is completely UP (the caller may not
930 * know all the variables of a server's state). This function will not change
931 * the weight of a server which was already up.
932 */
933static void fwlc_set_server_status_up(struct server *srv)
934{
935 struct proxy *p = srv->proxy;
936
937 if (srv->state == srv->prev_state &&
938 srv->eweight == srv->prev_eweight)
939 return;
940
941 if (!srv_is_usable(srv->state, srv->eweight))
942 goto out_update_state;
943
944 if (srv_is_usable(srv->prev_state, srv->prev_eweight))
945 /* server was already up */
946 goto out_update_backend;
947
948 if (srv->state & SRV_BACKUP) {
949 srv->lb_tree = &p->lbprm.fwlc.bck;
950 p->lbprm.tot_wbck += srv->eweight;
951 p->srv_bck++;
952
953 if (!(p->options & PR_O_USE_ALL_BK)) {
954 if (!p->lbprm.fbck) {
955 /* there was no backup server anymore */
956 p->lbprm.fbck = srv;
957 } else {
958 /* we may have restored a backup server prior to fbck,
959 * in which case it should replace it.
960 */
961 struct server *srv2 = srv;
962 do {
963 srv2 = srv2->next;
964 } while (srv2 && (srv2 != p->lbprm.fbck));
965 if (srv2)
966 p->lbprm.fbck = srv;
967 }
968 }
969 } else {
970 srv->lb_tree = &p->lbprm.fwlc.act;
971 p->lbprm.tot_wact += srv->eweight;
972 p->srv_act++;
973 }
974
975 /* note that eweight cannot be 0 here */
976 fwlc_queue_srv(srv);
977
978 out_update_backend:
979 /* check/update tot_used, tot_weight */
980 update_backend_weight(p);
981 out_update_state:
982 srv->prev_state = srv->state;
983 srv->prev_eweight = srv->eweight;
984}
985
986/* This function must be called after an update to server <srv>'s effective
987 * weight. It may be called after a state change too.
988 */
989static void fwlc_update_server_weight(struct server *srv)
990{
991 int old_state, new_state;
992 struct proxy *p = srv->proxy;
993
994 if (srv->state == srv->prev_state &&
995 srv->eweight == srv->prev_eweight)
996 return;
997
998 /* If changing the server's weight changes its state, we simply apply
999 * the procedures we already have for status change. If the state
1000 * remains down, the server is not in any tree, so it's as easy as
1001 * updating its values. If the state remains up with different weights,
1002 * there are some computations to perform to find a new place and
1003 * possibly a new tree for this server.
1004 */
1005
1006 old_state = srv_is_usable(srv->prev_state, srv->prev_eweight);
1007 new_state = srv_is_usable(srv->state, srv->eweight);
1008
1009 if (!old_state && !new_state) {
1010 srv->prev_state = srv->state;
1011 srv->prev_eweight = srv->eweight;
1012 return;
1013 }
1014 else if (!old_state && new_state) {
1015 fwlc_set_server_status_up(srv);
1016 return;
1017 }
1018 else if (old_state && !new_state) {
1019 fwlc_set_server_status_down(srv);
1020 return;
1021 }
1022
1023 if (srv->lb_tree)
1024 fwlc_dequeue_srv(srv);
1025
1026 if (srv->state & SRV_BACKUP) {
1027 p->lbprm.tot_wbck += srv->eweight - srv->prev_eweight;
1028 srv->lb_tree = &p->lbprm.fwlc.bck;
1029 } else {
1030 p->lbprm.tot_wact += srv->eweight - srv->prev_eweight;
1031 srv->lb_tree = &p->lbprm.fwlc.act;
1032 }
1033
1034 fwlc_queue_srv(srv);
1035
1036 update_backend_weight(p);
1037 srv->prev_state = srv->state;
1038 srv->prev_eweight = srv->eweight;
1039}
1040
1041/* This function is responsible for building the trees in case of fast
1042 * weighted least-conns. It also sets p->lbprm.wdiv to the eweight to
1043 * uweight ratio. Both active and backup groups are initialized.
1044 */
1045void fwlc_init_server_tree(struct proxy *p)
1046{
1047 struct server *srv;
1048 struct eb_root init_head = EB_ROOT;
1049
1050 p->lbprm.set_server_status_up = fwlc_set_server_status_up;
1051 p->lbprm.set_server_status_down = fwlc_set_server_status_down;
1052 p->lbprm.update_server_eweight = fwlc_update_server_weight;
1053 p->lbprm.server_take_conn = fwlc_srv_reposition;
1054 p->lbprm.server_drop_conn = fwlc_srv_reposition;
1055
1056 p->lbprm.wdiv = BE_WEIGHT_SCALE;
1057 for (srv = p->srv; srv; srv = srv->next) {
1058 srv->prev_eweight = srv->eweight = srv->uweight * BE_WEIGHT_SCALE;
1059 srv->prev_state = srv->state;
1060 }
1061
1062 recount_servers(p);
1063 update_backend_weight(p);
1064
1065 p->lbprm.fwlc.act = init_head;
1066 p->lbprm.fwlc.bck = init_head;
1067
1068 /* queue active and backup servers in two distinct groups */
1069 for (srv = p->srv; srv; srv = srv->next) {
1070 if (!srv_is_usable(srv->state, srv->eweight))
1071 continue;
1072 srv->lb_tree = (srv->state & SRV_BACKUP) ? &p->lbprm.fwlc.bck : &p->lbprm.fwlc.act;
1073 fwlc_queue_srv(srv);
1074 }
1075}
1076
1077/* Return next server from the FWLC tree in backend <p>. If the tree is empty,
1078 * return NULL. Saturated servers are skipped.
1079 */
1080static struct server *fwlc_get_next_server(struct proxy *p, struct server *srvtoavoid)
1081{
1082 struct server *srv, *avoided;
1083 struct eb32_node *node;
1084
1085 srv = avoided = NULL;
1086
1087 if (p->srv_act)
1088 node = eb32_first(&p->lbprm.fwlc.act);
1089 else if (p->lbprm.fbck)
1090 return p->lbprm.fbck;
1091 else if (p->srv_bck)
1092 node = eb32_first(&p->lbprm.fwlc.bck);
1093 else
1094 return NULL;
1095
1096 while (node) {
1097 /* OK, we have a server. However, it may be saturated, in which
1098 * case we don't want to reconsider it for now, so we'll simply
1099 * skip it. Same if it's the server we try to avoid, in which
1100 * case we simply remember it for later use if needed.
1101 */
1102 struct server *s;
1103
1104 s = eb32_entry(node, struct server, lb_node);
Willy Tarreau7c669d72008-06-20 15:04:11 +02001105 if (!s->maxconn || (!s->nbpend && s->served < srv_dynamic_maxconn(s))) {
Willy Tarreau51406232008-03-10 22:04:20 +01001106 if (s != srvtoavoid) {
1107 srv = s;
1108 break;
1109 }
1110 avoided = s;
1111 }
1112 node = eb32_next(node);
1113 }
1114
1115 if (!srv)
1116 srv = avoided;
1117
1118 return srv;
1119}
1120
Willy Tarreau01732802007-11-01 22:48:15 +01001121/*
1122 * This function tries to find a running server for the proxy <px> following
1123 * the URL parameter hash method. It looks for a specific parameter in the
1124 * URL and hashes it to compute the server ID. This is useful to optimize
1125 * performance by avoiding bounces between servers in contexts where sessions
1126 * are shared but cookies are not usable. If the parameter is not found, NULL
1127 * is returned. If any server is found, it will be returned. If no valid server
1128 * is found, NULL is returned.
Willy Tarreau01732802007-11-01 22:48:15 +01001129 */
1130struct server *get_server_ph(struct proxy *px, const char *uri, int uri_len)
1131{
1132 unsigned long hash = 0;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001133 const char *p;
1134 const char *params;
Willy Tarreau01732802007-11-01 22:48:15 +01001135 int plen;
1136
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001137 /* when tot_weight is 0 then so is srv_count */
Willy Tarreau20697042007-11-15 23:26:18 +01001138 if (px->lbprm.tot_weight == 0)
Willy Tarreau01732802007-11-01 22:48:15 +01001139 return NULL;
1140
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001141 if ((p = memchr(uri, '?', uri_len)) == NULL)
1142 return NULL;
1143
Willy Tarreau20697042007-11-15 23:26:18 +01001144 if (px->lbprm.map.state & PR_MAP_RECALC)
1145 recalc_server_map(px);
1146
Willy Tarreau01732802007-11-01 22:48:15 +01001147 p++;
1148
1149 uri_len -= (p - uri);
1150 plen = px->url_param_len;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001151 params = p;
Willy Tarreau01732802007-11-01 22:48:15 +01001152
1153 while (uri_len > plen) {
1154 /* Look for the parameter name followed by an equal symbol */
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001155 if (params[plen] == '=') {
1156 if (memcmp(params, px->url_param_name, plen) == 0) {
1157 /* OK, we have the parameter here at <params>, and
Willy Tarreau01732802007-11-01 22:48:15 +01001158 * the value after the equal sign, at <p>
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001159 * skip the equal symbol
Willy Tarreau01732802007-11-01 22:48:15 +01001160 */
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001161 p += plen + 1;
1162 uri_len -= plen + 1;
1163
Willy Tarreau01732802007-11-01 22:48:15 +01001164 while (uri_len && *p != '&') {
1165 hash = *p + (hash << 6) + (hash << 16) - hash;
1166 uri_len--;
1167 p++;
1168 }
Willy Tarreau20697042007-11-15 23:26:18 +01001169 return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
Willy Tarreau01732802007-11-01 22:48:15 +01001170 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001171 }
1172 /* skip to next parameter */
1173 p = memchr(params, '&', uri_len);
1174 if (!p)
1175 return NULL;
1176 p++;
1177 uri_len -= (p - params);
1178 params = p;
1179 }
1180 return NULL;
1181}
1182
1183/*
1184 * this does the same as the previous server_ph, but check the body contents
1185 */
1186struct server *get_server_ph_post(struct session *s)
1187{
1188 unsigned long hash = 0;
1189 struct http_txn *txn = &s->txn;
1190 struct buffer *req = s->req;
1191 struct http_msg *msg = &txn->req;
1192 struct proxy *px = s->be;
1193 unsigned int plen = px->url_param_len;
Willy Tarreau192ee3e2008-04-19 21:24:56 +02001194 unsigned long body;
1195 unsigned long len;
1196 const char *params;
1197 struct hdr_ctx ctx;
1198 const char *p;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001199
1200 /* tot_weight appears to mean srv_count */
1201 if (px->lbprm.tot_weight == 0)
1202 return NULL;
1203
Willy Tarreau192ee3e2008-04-19 21:24:56 +02001204 body = msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1;
Willy Tarreaufb0528b2008-08-11 00:21:56 +02001205 len = req->l - body;
Willy Tarreau192ee3e2008-04-19 21:24:56 +02001206 params = req->data + body;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001207
1208 if ( len == 0 )
1209 return NULL;
1210
1211 if (px->lbprm.map.state & PR_MAP_RECALC)
1212 recalc_server_map(px);
1213
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001214 ctx.idx = 0;
1215
1216 /* if the message is chunked, we skip the chunk size, but use the value as len */
1217 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
Willy Tarreauadfb8562008-08-11 15:24:42 +02001218 if (ctx.idx && ctx.vlen >= 7 && strncasecmp(ctx.line+ctx.val, "chunked", 7) == 0) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001219 unsigned int chunk = 0;
Willy Tarreau03d60bb2009-01-09 11:13:00 +01001220 while ( params < (req->data+req->max_len) && !HTTP_IS_CRLF(*params)) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001221 char c = *params;
1222 if (ishex(c)) {
1223 unsigned int hex = toupper(c) - '0';
1224 if ( hex > 9 )
1225 hex -= 'A' - '9' - 1;
1226 chunk = (chunk << 4) | hex;
1227 }
1228 else
1229 return NULL;
1230 params++;
1231 len--;
Willy Tarreau01732802007-11-01 22:48:15 +01001232 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001233 /* spec says we get CRLF */
1234 if (HTTP_IS_CRLF(*params) && HTTP_IS_CRLF(params[1]))
1235 params += 2;
1236 else
1237 return NULL;
1238 /* ok we have some encoded length, just inspect the first chunk */
1239 len = chunk;
1240 }
Willy Tarreau01732802007-11-01 22:48:15 +01001241
Willy Tarreau192ee3e2008-04-19 21:24:56 +02001242 p = params;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001243
1244 while (len > plen) {
1245 /* Look for the parameter name followed by an equal symbol */
1246 if (params[plen] == '=') {
1247 if (memcmp(params, px->url_param_name, plen) == 0) {
1248 /* OK, we have the parameter here at <params>, and
1249 * the value after the equal sign, at <p>
1250 * skip the equal symbol
1251 */
1252 p += plen + 1;
1253 len -= plen + 1;
1254
1255 while (len && *p != '&') {
1256 if (unlikely(!HTTP_IS_TOKEN(*p))) {
1257 /* if in a POST, body must be URI encoded or its not a URI.
1258 * Do not interprete any possible binary data as a parameter.
1259 */
1260 if (likely(HTTP_IS_LWS(*p))) /* eol, uncertain uri len */
1261 break;
1262 return NULL; /* oh, no; this is not uri-encoded.
1263 * This body does not contain parameters.
1264 */
1265 }
1266 hash = *p + (hash << 6) + (hash << 16) - hash;
1267 len--;
1268 p++;
1269 /* should we break if vlen exceeds limit? */
1270 }
1271 return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
1272 }
1273 }
Willy Tarreau01732802007-11-01 22:48:15 +01001274 /* skip to next parameter */
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001275 p = memchr(params, '&', len);
Willy Tarreau01732802007-11-01 22:48:15 +01001276 if (!p)
1277 return NULL;
1278 p++;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001279 len -= (p - params);
1280 params = p;
Willy Tarreau01732802007-11-01 22:48:15 +01001281 }
1282 return NULL;
1283}
Willy Tarreaubaaee002006-06-26 02:48:02 +02001284
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001285
Willy Tarreaubaaee002006-06-26 02:48:02 +02001286/*
Benoitaffb4812009-03-25 13:02:10 +01001287 * This function tries to find a running server for the proxy <px> following
1288 * the Header parameter hash method. It looks for a specific parameter in the
1289 * URL and hashes it to compute the server ID. This is useful to optimize
1290 * performance by avoiding bounces between servers in contexts where sessions
1291 * are shared but cookies are not usable. If the parameter is not found, NULL
1292 * is returned. If any server is found, it will be returned. If no valid server
1293 * is found, NULL is returned.
1294 */
1295struct server *get_server_hh(struct session *s)
1296{
1297 unsigned long hash = 0;
1298 struct http_txn *txn = &s->txn;
1299 struct http_msg *msg = &txn->req;
1300 struct proxy *px = s->be;
1301 unsigned int plen = px->hh_len;
1302 unsigned long len;
1303 struct hdr_ctx ctx;
1304 const char *p;
1305
1306 /* tot_weight appears to mean srv_count */
1307 if (px->lbprm.tot_weight == 0)
1308 return NULL;
1309
1310 if (px->lbprm.map.state & PR_MAP_RECALC)
1311 recalc_server_map(px);
1312
1313 ctx.idx = 0;
1314
1315 /* if the message is chunked, we skip the chunk size, but use the value as len */
1316 http_find_header2(px->hh_name, plen, msg->sol, &txn->hdr_idx, &ctx);
1317
1318 /* if the header is not found or empty, let's fallback to round robin */
1319 if (!ctx.idx || !ctx.vlen)
1320 return NULL;
1321
1322 /* Found a the hh_name in the headers.
1323 * we will compute the hash based on this value ctx.val.
1324 */
1325 len = ctx.vlen;
1326 p = (char *)ctx.line + ctx.val;
1327 if (!px->hh_match_domain) {
1328 while (len) {
1329 hash = *p + (hash << 6) + (hash << 16) - hash;
1330 len--;
1331 p++;
1332 }
1333 } else {
1334 int dohash = 0;
1335 p += len - 1;
1336 /* special computation, use only main domain name, not tld/host
1337 * going back from the end of string, start hashing at first
1338 * dot stop at next.
1339 * This is designed to work with the 'Host' header, and requires
1340 * a special option to activate this.
1341 */
1342 while (len) {
1343 if (*p == '.') {
1344 if (!dohash)
1345 dohash = 1;
1346 else
1347 break;
1348 } else {
1349 if (dohash)
1350 hash = *p + (hash << 6) + (hash << 16) - hash;
1351 }
1352 len--;
1353 p--;
1354 }
1355 }
1356 return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
1357}
1358
Emeric Brun736aa232009-06-30 17:56:00 +02001359struct server *get_server_rch(struct session *s)
1360{
1361 unsigned long hash = 0;
1362 struct proxy *px = s->be;
1363 unsigned long len;
1364 const char *p;
1365 int ret;
1366 struct acl_expr expr;
1367 struct acl_test test;
1368
1369 /* tot_weight appears to mean srv_count */
1370 if (px->lbprm.tot_weight == 0)
1371 return NULL;
1372
1373 if (px->lbprm.map.state & PR_MAP_RECALC)
1374 recalc_server_map(px);
1375
1376 memset(&expr, 0, sizeof(expr));
1377 memset(&test, 0, sizeof(test));
1378
1379 expr.arg.str = px->hh_name;
1380 expr.arg_len = px->hh_len;
1381
1382 ret = acl_fetch_rdp_cookie(px, s, NULL, ACL_DIR_REQ, &expr, &test);
1383 if (ret == 0 || (test.flags & ACL_TEST_F_MAY_CHANGE) || test.len == 0)
1384 return NULL;
1385
1386 /* Found a the hh_name in the headers.
1387 * we will compute the hash based on this value ctx.val.
1388 */
1389 len = test.len;
1390 p = (char *)test.ptr;
1391 while (len) {
1392 hash = *p + (hash << 6) + (hash << 16) - hash;
1393 len--;
1394 p++;
1395 }
1396
1397 return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
1398}
Benoitaffb4812009-03-25 13:02:10 +01001399
1400/*
Willy Tarreau7c669d72008-06-20 15:04:11 +02001401 * This function applies the load-balancing algorithm to the session, as
1402 * defined by the backend it is assigned to. The session is then marked as
1403 * 'assigned'.
1404 *
1405 * This function MAY NOT be called with SN_ASSIGNED already set. If the session
1406 * had a server previously assigned, it is rebalanced, trying to avoid the same
1407 * server.
1408 * The function tries to keep the original connection slot if it reconnects to
1409 * the same server, otherwise it releases it and tries to offer it.
1410 *
1411 * It is illegal to call this function with a session in a queue.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001412 *
1413 * It may return :
Willy Tarreau7c669d72008-06-20 15:04:11 +02001414 * SRV_STATUS_OK if everything is OK. Session assigned to ->srv
1415 * SRV_STATUS_NOSRV if no server is available. Session is not ASSIGNED
1416 * SRV_STATUS_FULL if all servers are saturated. Session is not ASSIGNED
Willy Tarreaubaaee002006-06-26 02:48:02 +02001417 * SRV_STATUS_INTERNAL for other unrecoverable errors.
1418 *
Willy Tarreau7c669d72008-06-20 15:04:11 +02001419 * Upon successful return, the session flag SN_ASSIGNED is set to indicate that
1420 * it does not need to be called anymore. This means that s->srv can be trusted
1421 * in balance and direct modes.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001422 *
1423 */
1424
1425int assign_server(struct session *s)
1426{
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001427
Willy Tarreau7c669d72008-06-20 15:04:11 +02001428 struct server *conn_slot;
1429 int err;
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001430
Willy Tarreaubaaee002006-06-26 02:48:02 +02001431#ifdef DEBUG_FULL
1432 fprintf(stderr,"assign_server : s=%p\n",s);
1433#endif
1434
Willy Tarreau7c669d72008-06-20 15:04:11 +02001435 err = SRV_STATUS_INTERNAL;
1436 if (unlikely(s->pend_pos || s->flags & SN_ASSIGNED))
1437 goto out_err;
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001438
Willy Tarreau7c669d72008-06-20 15:04:11 +02001439 s->prev_srv = s->prev_srv;
1440 conn_slot = s->srv_conn;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001441
Willy Tarreau7c669d72008-06-20 15:04:11 +02001442 /* We have to release any connection slot before applying any LB algo,
1443 * otherwise we may erroneously end up with no available slot.
1444 */
1445 if (conn_slot)
1446 sess_change_server(s, NULL);
1447
1448 /* We will now try to find the good server and store it into <s->srv>.
1449 * Note that <s->srv> may be NULL in case of dispatch or proxy mode,
1450 * as well as if no server is available (check error code).
1451 */
Willy Tarreau1a20a5d2007-11-01 21:08:19 +01001452
Willy Tarreau7c669d72008-06-20 15:04:11 +02001453 s->srv = NULL;
1454 if (s->be->lbprm.algo & BE_LB_ALGO) {
1455 int len;
1456 /* we must check if we have at least one server available */
1457 if (!s->be->lbprm.tot_weight) {
1458 err = SRV_STATUS_NOSRV;
1459 goto out;
1460 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001461
Willy Tarreau7c669d72008-06-20 15:04:11 +02001462 switch (s->be->lbprm.algo & BE_LB_ALGO) {
1463 case BE_LB_ALGO_RR:
1464 s->srv = fwrr_get_next_server(s->be, s->prev_srv);
1465 if (!s->srv) {
1466 err = SRV_STATUS_FULL;
1467 goto out;
1468 }
1469 break;
1470 case BE_LB_ALGO_LC:
1471 s->srv = fwlc_get_next_server(s->be, s->prev_srv);
1472 if (!s->srv) {
1473 err = SRV_STATUS_FULL;
1474 goto out;
1475 }
1476 break;
1477 case BE_LB_ALGO_SH:
1478 if (s->cli_addr.ss_family == AF_INET)
1479 len = 4;
1480 else if (s->cli_addr.ss_family == AF_INET6)
1481 len = 16;
1482 else {
1483 /* unknown IP family */
1484 err = SRV_STATUS_INTERNAL;
1485 goto out;
1486 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001487
Willy Tarreau7c669d72008-06-20 15:04:11 +02001488 s->srv = get_server_sh(s->be,
1489 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
1490 len);
1491 break;
1492 case BE_LB_ALGO_UH:
1493 /* URI hashing */
1494 s->srv = get_server_uh(s->be,
1495 s->txn.req.sol + s->txn.req.sl.rq.u,
1496 s->txn.req.sl.rq.u_l);
1497 break;
1498 case BE_LB_ALGO_PH:
1499 /* URL Parameter hashing */
1500 if (s->txn.meth == HTTP_METH_POST &&
1501 memchr(s->txn.req.sol + s->txn.req.sl.rq.u, '&',
1502 s->txn.req.sl.rq.u_l ) == NULL)
1503 s->srv = get_server_ph_post(s);
1504 else
1505 s->srv = get_server_ph(s->be,
Willy Tarreau2fcb5002007-05-08 13:35:26 +02001506 s->txn.req.sol + s->txn.req.sl.rq.u,
1507 s->txn.req.sl.rq.u_l);
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001508
Willy Tarreau7c669d72008-06-20 15:04:11 +02001509 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);
Willy Tarreau01732802007-11-01 22:48:15 +01001512 if (!s->srv) {
Willy Tarreau7c669d72008-06-20 15:04:11 +02001513 err = SRV_STATUS_FULL;
1514 goto out;
Willy Tarreau01732802007-11-01 22:48:15 +01001515 }
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001516 }
Willy Tarreau7c669d72008-06-20 15:04:11 +02001517 break;
Benoitaffb4812009-03-25 13:02:10 +01001518 case BE_LB_ALGO_HH:
1519 /* Header Parameter hashing */
1520 s->srv = get_server_hh(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;
Emeric Brun736aa232009-06-30 17:56:00 +02001531 case BE_LB_ALGO_RCH:
1532 /* RDP Cookie hashing */
1533 s->srv = get_server_rch(s);
1534
1535 if (!s->srv) {
1536 /* parameter not found, fall back to round robin on the map */
1537 s->srv = get_server_rr_with_conns(s->be, s->prev_srv);
1538 if (!s->srv) {
1539 err = SRV_STATUS_FULL;
1540 goto out;
1541 }
1542 }
1543 break;
Willy Tarreau7c669d72008-06-20 15:04:11 +02001544 default:
1545 /* unknown balancing algorithm */
1546 err = SRV_STATUS_INTERNAL;
1547 goto out;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001548 }
Willy Tarreau7c669d72008-06-20 15:04:11 +02001549 if (s->srv != s->prev_srv) {
1550 s->be->cum_lbconn++;
1551 s->srv->cum_lbconn++;
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01001552 }
Willy Tarreau7c669d72008-06-20 15:04:11 +02001553 }
1554 else if (s->be->options & PR_O_HTTP_PROXY) {
1555 if (!s->srv_addr.sin_addr.s_addr) {
1556 err = SRV_STATUS_NOSRV;
1557 goto out;
Willy Tarreau5d65bbb2007-01-21 12:47:26 +01001558 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001559 }
Willy Tarreau7c669d72008-06-20 15:04:11 +02001560 else if (!*(int *)&s->be->dispatch_addr.sin_addr &&
Willy Tarreau4b1f8592008-12-23 23:13:55 +01001561 !(s->be->options & PR_O_TRANSP)) {
Willy Tarreau7c669d72008-06-20 15:04:11 +02001562 err = SRV_STATUS_NOSRV;
1563 goto out;
1564 }
1565
1566 s->flags |= SN_ASSIGNED;
1567 err = SRV_STATUS_OK;
1568 out:
1569
1570 /* Either we take back our connection slot, or we offer it to someone
1571 * else if we don't need it anymore.
1572 */
1573 if (conn_slot) {
1574 if (conn_slot == s->srv) {
1575 sess_change_server(s, s->srv);
1576 } else {
1577 if (may_dequeue_tasks(conn_slot, s->be))
1578 process_srv_queue(conn_slot);
1579 }
1580 }
1581
1582 out_err:
1583 return err;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001584}
1585
1586
1587/*
1588 * This function assigns a server address to a session, and sets SN_ADDR_SET.
1589 * The address is taken from the currently assigned server, or from the
1590 * dispatch or transparent address.
1591 *
1592 * It may return :
1593 * SRV_STATUS_OK if everything is OK.
1594 * SRV_STATUS_INTERNAL for other unrecoverable errors.
1595 *
1596 * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
1597 * not cleared, so it's to the caller to clear it if required.
1598 *
1599 */
1600int assign_server_address(struct session *s)
1601{
1602#ifdef DEBUG_FULL
1603 fprintf(stderr,"assign_server_address : s=%p\n",s);
1604#endif
1605
Willy Tarreau31682232007-11-29 15:38:04 +01001606 if ((s->flags & SN_DIRECT) || (s->be->lbprm.algo & BE_LB_ALGO)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001607 /* A server is necessarily known for this session */
1608 if (!(s->flags & SN_ASSIGNED))
1609 return SRV_STATUS_INTERNAL;
1610
1611 s->srv_addr = s->srv->addr;
1612
1613 /* if this server remaps proxied ports, we'll use
1614 * the port the client connected to with an offset. */
1615 if (s->srv->state & SRV_MAPPORTS) {
Willy Tarreau4b1f8592008-12-23 23:13:55 +01001616 if (!(s->be->options & PR_O_TRANSP) && !(s->flags & SN_FRT_ADDR_SET))
Willy Tarreau14c8aac2007-05-08 19:46:30 +02001617 get_frt_addr(s);
1618 if (s->frt_addr.ss_family == AF_INET) {
1619 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) +
1620 ntohs(((struct sockaddr_in *)&s->frt_addr)->sin_port));
1621 } else {
1622 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) +
1623 ntohs(((struct sockaddr_in6 *)&s->frt_addr)->sin6_port));
1624 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001625 }
1626 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001627 else if (*(int *)&s->be->dispatch_addr.sin_addr) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001628 /* connect to the defined dispatch addr */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001629 s->srv_addr = s->be->dispatch_addr;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001630 }
Willy Tarreau4b1f8592008-12-23 23:13:55 +01001631 else if (s->be->options & PR_O_TRANSP) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001632 /* in transparent mode, use the original dest addr if no dispatch specified */
Willy Tarreaubd414282008-01-19 13:46:35 +01001633 if (!(s->flags & SN_FRT_ADDR_SET))
1634 get_frt_addr(s);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001635
Willy Tarreaubd414282008-01-19 13:46:35 +01001636 memcpy(&s->srv_addr, &s->frt_addr, MIN(sizeof(s->srv_addr), sizeof(s->frt_addr)));
1637 /* when we support IPv6 on the backend, we may add other tests */
1638 //qfprintf(stderr, "Cannot get original server address.\n");
1639 //return SRV_STATUS_INTERNAL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001640 }
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01001641 else if (s->be->options & PR_O_HTTP_PROXY) {
1642 /* If HTTP PROXY option is set, then server is already assigned
1643 * during incoming client request parsing. */
1644 }
Willy Tarreau1a1158b2007-01-20 11:07:46 +01001645 else {
1646 /* no server and no LB algorithm ! */
1647 return SRV_STATUS_INTERNAL;
1648 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001649
1650 s->flags |= SN_ADDR_SET;
1651 return SRV_STATUS_OK;
1652}
1653
1654
1655/* This function assigns a server to session <s> if required, and can add the
1656 * connection to either the assigned server's queue or to the proxy's queue.
Willy Tarreau7c669d72008-06-20 15:04:11 +02001657 * If ->srv_conn is set, the session is first released from the server.
1658 * It may also be called with SN_DIRECT and/or SN_ASSIGNED though. It will
1659 * be called before any connection and after any retry or redispatch occurs.
1660 *
1661 * It is not allowed to call this function with a session in a queue.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001662 *
1663 * Returns :
1664 *
1665 * SRV_STATUS_OK if everything is OK.
1666 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
1667 * SRV_STATUS_QUEUED if the connection has been queued.
1668 * SRV_STATUS_FULL if the server(s) is/are saturated and the
Willy Tarreau7c669d72008-06-20 15:04:11 +02001669 * connection could not be queued in s->srv,
1670 * which may be NULL if we queue on the backend.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001671 * SRV_STATUS_INTERNAL for other unrecoverable errors.
1672 *
1673 */
1674int assign_server_and_queue(struct session *s)
1675{
1676 struct pendconn *p;
1677 int err;
1678
1679 if (s->pend_pos)
1680 return SRV_STATUS_INTERNAL;
1681
Willy Tarreau7c669d72008-06-20 15:04:11 +02001682 err = SRV_STATUS_OK;
1683 if (!(s->flags & SN_ASSIGNED)) {
1684 err = assign_server(s);
1685 if (s->prev_srv) {
1686 /* This session was previously assigned to a server. We have to
1687 * update the session's and the server's stats :
1688 * - if the server changed :
1689 * - set TX_CK_DOWN if txn.flags was TX_CK_VALID
1690 * - set SN_REDISP if it was successfully redispatched
1691 * - increment srv->redispatches and be->redispatches
1692 * - if the server remained the same : update retries.
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001693 */
1694
Willy Tarreau7c669d72008-06-20 15:04:11 +02001695 if (s->prev_srv != s->srv) {
1696 if ((s->txn.flags & TX_CK_MASK) == TX_CK_VALID) {
1697 s->txn.flags &= ~TX_CK_MASK;
1698 s->txn.flags |= TX_CK_DOWN;
1699 }
1700 s->flags |= SN_REDISP;
1701 s->prev_srv->redispatches++;
1702 s->be->redispatches++;
1703 } else {
1704 s->prev_srv->retries++;
1705 s->be->retries++;
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001706 }
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001707 }
1708 }
1709
Willy Tarreaubaaee002006-06-26 02:48:02 +02001710 switch (err) {
1711 case SRV_STATUS_OK:
Willy Tarreau7c669d72008-06-20 15:04:11 +02001712 /* we have SN_ASSIGNED set */
1713 if (!s->srv)
1714 return SRV_STATUS_OK; /* dispatch or proxy mode */
1715
1716 /* If we already have a connection slot, no need to check any queue */
1717 if (s->srv_conn == s->srv)
1718 return SRV_STATUS_OK;
1719
1720 /* OK, this session already has an assigned server, but no
1721 * connection slot yet. Either it is a redispatch, or it was
1722 * assigned from persistence information (direct mode).
1723 */
1724 if ((s->flags & SN_REDIRECTABLE) && s->srv->rdr_len) {
1725 /* server scheduled for redirection, and already assigned. We
1726 * don't want to go further nor check the queue.
Willy Tarreau21d2af32008-02-14 20:25:24 +01001727 */
Willy Tarreau7c669d72008-06-20 15:04:11 +02001728 sess_change_server(s, s->srv); /* not really needed in fact */
Willy Tarreau21d2af32008-02-14 20:25:24 +01001729 return SRV_STATUS_OK;
1730 }
1731
Willy Tarreau7c669d72008-06-20 15:04:11 +02001732 /* We might have to queue this session if the assigned server is full.
1733 * We know we have to queue it into the server's queue, so if a maxqueue
1734 * is set on the server, we must also check that the server's queue is
1735 * not full, in which case we have to return FULL.
1736 */
1737 if (s->srv->maxconn &&
1738 (s->srv->nbpend || s->srv->served >= srv_dynamic_maxconn(s->srv))) {
1739
1740 if (s->srv->maxqueue > 0 && s->srv->nbpend >= s->srv->maxqueue)
1741 return SRV_STATUS_FULL;
1742
Willy Tarreaubaaee002006-06-26 02:48:02 +02001743 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 }
Willy Tarreau7c669d72008-06-20 15:04:11 +02001749
1750 /* OK, we can use this server. Let's reserve our place */
1751 sess_change_server(s, s->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001752 return SRV_STATUS_OK;
1753
1754 case SRV_STATUS_FULL:
1755 /* queue this session into the proxy's queue */
1756 p = pendconn_add(s);
1757 if (p)
1758 return SRV_STATUS_QUEUED;
1759 else
Willy Tarreau7c669d72008-06-20 15:04:11 +02001760 return SRV_STATUS_INTERNAL;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001761
1762 case SRV_STATUS_NOSRV:
Willy Tarreau7c669d72008-06-20 15:04:11 +02001763 return err;
1764
Willy Tarreaubaaee002006-06-26 02:48:02 +02001765 case SRV_STATUS_INTERNAL:
1766 return err;
Willy Tarreau7c669d72008-06-20 15:04:11 +02001767
Willy Tarreaubaaee002006-06-26 02:48:02 +02001768 default:
1769 return SRV_STATUS_INTERNAL;
1770 }
Willy Tarreau5b6995c2008-01-13 16:31:17 +01001771}
Willy Tarreaubaaee002006-06-26 02:48:02 +02001772
1773/*
1774 * This function initiates a connection to the server assigned to this session
1775 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
1776 * It can return one of :
1777 * - SN_ERR_NONE if everything's OK
1778 * - SN_ERR_SRVTO if there are no more servers
1779 * - SN_ERR_SRVCL if the connection was refused by the server
1780 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1781 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1782 * - SN_ERR_INTERNAL for any other purely internal errors
1783 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
1784 */
1785int connect_server(struct session *s)
1786{
Willy Tarreau9650f372009-08-16 14:02:45 +02001787 int err;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001788
1789 if (!(s->flags & SN_ADDR_SET)) {
1790 err = assign_server_address(s);
1791 if (err != SRV_STATUS_OK)
1792 return SN_ERR_INTERNAL;
1793 }
1794
Willy Tarreau9650f372009-08-16 14:02:45 +02001795 if (!s->req->cons->connect)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001796 return SN_ERR_INTERNAL;
Willy Tarreaud88edf22009-06-14 15:48:17 +02001797
Willy Tarreau9650f372009-08-16 14:02:45 +02001798 err = s->req->cons->connect(s->req->cons, s->be, s->srv,
1799 (struct sockaddr *)&s->srv_addr,
1800 (struct sockaddr *)&s->cli_addr);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001801
Willy Tarreau9650f372009-08-16 14:02:45 +02001802 if (err != SN_ERR_NONE)
1803 return err;
Willy Tarreau788e2842008-08-26 13:25:39 +02001804
Willy Tarreaubaaee002006-06-26 02:48:02 +02001805 if (s->srv) {
Willy Tarreau1e62de62008-11-11 20:20:02 +01001806 s->flags |= SN_CURR_SESS;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001807 s->srv->cur_sess++;
1808 if (s->srv->cur_sess > s->srv->cur_sess_max)
1809 s->srv->cur_sess_max = s->srv->cur_sess;
Willy Tarreau51406232008-03-10 22:04:20 +01001810 if (s->be->lbprm.server_take_conn)
1811 s->be->lbprm.server_take_conn(s->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001812 }
1813
Willy Tarreaubaaee002006-06-26 02:48:02 +02001814 return SN_ERR_NONE; /* connection is OK */
1815}
1816
1817
Willy Tarreaubaaee002006-06-26 02:48:02 +02001818/* This function performs the "redispatch" part of a connection attempt. It
1819 * will assign a server if required, queue the connection if required, and
1820 * handle errors that might arise at this level. It can change the server
1821 * state. It will return 1 if it encounters an error, switches the server
1822 * state, or has to queue a connection. Otherwise, it will return 0 indicating
1823 * that the connection is ready to use.
1824 */
1825
1826int srv_redispatch_connect(struct session *t)
1827{
1828 int conn_err;
1829
1830 /* We know that we don't have any connection pending, so we will
1831 * try to get a new one, and wait in this state if it's queued
1832 */
Willy Tarreau7c669d72008-06-20 15:04:11 +02001833 redispatch:
Willy Tarreaubaaee002006-06-26 02:48:02 +02001834 conn_err = assign_server_and_queue(t);
1835 switch (conn_err) {
1836 case SRV_STATUS_OK:
1837 break;
1838
Willy Tarreau7c669d72008-06-20 15:04:11 +02001839 case SRV_STATUS_FULL:
1840 /* The server has reached its maxqueue limit. Either PR_O_REDISP is set
1841 * and we can redispatch to another server, or it is not and we return
1842 * 503. This only makes sense in DIRECT mode however, because normal LB
1843 * algorithms would never select such a server, and hash algorithms
1844 * would bring us on the same server again. Note that t->srv is set in
1845 * this case.
1846 */
1847 if ((t->flags & SN_DIRECT) && (t->be->options & PR_O_REDISP)) {
1848 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
1849 t->prev_srv = t->srv;
1850 goto redispatch;
1851 }
1852
Willy Tarreaufa7e1022008-10-19 07:30:41 +02001853 if (!t->req->cons->err_type) {
1854 t->req->cons->err_type = SI_ET_QUEUE_ERR;
1855 t->req->cons->err_loc = t->srv;
1856 }
Willy Tarreau7c669d72008-06-20 15:04:11 +02001857
1858 t->srv->failed_conns++;
1859 t->be->failed_conns++;
1860 return 1;
1861
Willy Tarreaubaaee002006-06-26 02:48:02 +02001862 case SRV_STATUS_NOSRV:
1863 /* note: it is guaranteed that t->srv == NULL here */
Willy Tarreaufa7e1022008-10-19 07:30:41 +02001864 if (!t->req->cons->err_type) {
1865 t->req->cons->err_type = SI_ET_CONN_ERR;
1866 t->req->cons->err_loc = NULL;
1867 }
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01001868
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001869 t->be->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001870 return 1;
1871
1872 case SRV_STATUS_QUEUED:
Willy Tarreau35374672008-09-03 18:11:02 +02001873 t->req->cons->exp = tick_add_ifset(now_ms, t->be->timeout.queue);
Willy Tarreaufa7e1022008-10-19 07:30:41 +02001874 t->req->cons->state = SI_ST_QUE;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001875 /* do nothing else and do not wake any other session up */
1876 return 1;
1877
Willy Tarreaubaaee002006-06-26 02:48:02 +02001878 case SRV_STATUS_INTERNAL:
1879 default:
Willy Tarreaufa7e1022008-10-19 07:30:41 +02001880 if (!t->req->cons->err_type) {
1881 t->req->cons->err_type = SI_ET_CONN_OTHER;
1882 t->req->cons->err_loc = t->srv;
1883 }
1884
Willy Tarreaubaaee002006-06-26 02:48:02 +02001885 if (t->srv)
Willy Tarreau7f062c42009-03-05 18:43:00 +01001886 srv_inc_sess_ctr(t->srv);
Willy Tarreau98937b82007-12-10 15:05:42 +01001887 if (t->srv)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001888 t->srv->failed_conns++;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001889 t->be->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001890
1891 /* release other sessions waiting for this server */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001892 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001893 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001894 return 1;
1895 }
1896 /* if we get here, it's because we got SRV_STATUS_OK, which also
1897 * means that the connection has not been queued.
1898 */
1899 return 0;
1900}
1901
Krzysztof Oledzki85130942007-10-22 16:21:10 +02001902int be_downtime(struct proxy *px) {
Willy Tarreaub625a082007-11-26 01:15:43 +01001903 if (px->lbprm.tot_weight && px->last_change < now.tv_sec) // ignore negative time
Krzysztof Oledzki85130942007-10-22 16:21:10 +02001904 return px->down_time;
1905
1906 return now.tv_sec - px->last_change + px->down_time;
1907}
Willy Tarreaubaaee002006-06-26 02:48:02 +02001908
Willy Tarreaua0cbda62007-11-01 21:39:54 +01001909/* This function parses a "balance" statement in a backend section describing
1910 * <curproxy>. It returns -1 if there is any error, otherwise zero. If it
1911 * returns -1, it may write an error message into ther <err> buffer, for at
1912 * most <errlen> bytes, trailing zero included. The trailing '\n' will not be
1913 * written. The function must be called with <args> pointing to the first word
1914 * after "balance".
1915 */
1916int backend_parse_balance(const char **args, char *err, int errlen, struct proxy *curproxy)
1917{
1918 if (!*(args[0])) {
1919 /* if no option is set, use round-robin by default */
Willy Tarreau31682232007-11-29 15:38:04 +01001920 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1921 curproxy->lbprm.algo |= BE_LB_ALGO_RR;
Willy Tarreaua0cbda62007-11-01 21:39:54 +01001922 return 0;
1923 }
1924
1925 if (!strcmp(args[0], "roundrobin")) {
Willy Tarreau31682232007-11-29 15:38:04 +01001926 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1927 curproxy->lbprm.algo |= BE_LB_ALGO_RR;
Willy Tarreaua0cbda62007-11-01 21:39:54 +01001928 }
Willy Tarreau51406232008-03-10 22:04:20 +01001929 else if (!strcmp(args[0], "leastconn")) {
1930 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1931 curproxy->lbprm.algo |= BE_LB_ALGO_LC;
1932 }
Willy Tarreaua0cbda62007-11-01 21:39:54 +01001933 else if (!strcmp(args[0], "source")) {
Willy Tarreau31682232007-11-29 15:38:04 +01001934 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1935 curproxy->lbprm.algo |= BE_LB_ALGO_SH;
Willy Tarreaua0cbda62007-11-01 21:39:54 +01001936 }
1937 else if (!strcmp(args[0], "uri")) {
Marek Majkowski9c30fc12008-04-27 23:25:55 +02001938 int arg = 1;
1939
Willy Tarreau31682232007-11-29 15:38:04 +01001940 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1941 curproxy->lbprm.algo |= BE_LB_ALGO_UH;
Marek Majkowski9c30fc12008-04-27 23:25:55 +02001942
1943 while (*args[arg]) {
1944 if (!strcmp(args[arg], "len")) {
1945 if (!*args[arg+1] || (atoi(args[arg+1]) <= 0)) {
1946 snprintf(err, errlen, "'balance uri len' expects a positive integer (got '%s').", args[arg+1]);
1947 return -1;
1948 }
1949 curproxy->uri_len_limit = atoi(args[arg+1]);
1950 arg += 2;
1951 }
1952 else if (!strcmp(args[arg], "depth")) {
1953 if (!*args[arg+1] || (atoi(args[arg+1]) <= 0)) {
1954 snprintf(err, errlen, "'balance uri depth' expects a positive integer (got '%s').", args[arg+1]);
1955 return -1;
1956 }
1957 /* hint: we store the position of the ending '/' (depth+1) so
1958 * that we avoid a comparison while computing the hash.
1959 */
1960 curproxy->uri_dirs_depth1 = atoi(args[arg+1]) + 1;
1961 arg += 2;
1962 }
1963 else {
1964 snprintf(err, errlen, "'balance uri' only accepts parameters 'len' and 'depth' (got '%s').", args[arg]);
1965 return -1;
1966 }
1967 }
Willy Tarreaua0cbda62007-11-01 21:39:54 +01001968 }
Willy Tarreau01732802007-11-01 22:48:15 +01001969 else if (!strcmp(args[0], "url_param")) {
1970 if (!*args[1]) {
1971 snprintf(err, errlen, "'balance url_param' requires an URL parameter name.");
1972 return -1;
1973 }
Willy Tarreau31682232007-11-29 15:38:04 +01001974 curproxy->lbprm.algo &= ~BE_LB_ALGO;
1975 curproxy->lbprm.algo |= BE_LB_ALGO_PH;
Willy Tarreaua534fea2008-08-03 12:19:50 +02001976
1977 free(curproxy->url_param_name);
Willy Tarreau01732802007-11-01 22:48:15 +01001978 curproxy->url_param_name = strdup(args[1]);
Willy Tarreaua534fea2008-08-03 12:19:50 +02001979 curproxy->url_param_len = strlen(args[1]);
Marek Majkowski9c30fc12008-04-27 23:25:55 +02001980 if (*args[2]) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02001981 if (strcmp(args[2], "check_post")) {
1982 snprintf(err, errlen, "'balance url_param' only accepts check_post modifier.");
1983 return -1;
1984 }
1985 if (*args[3]) {
1986 /* TODO: maybe issue a warning if there is no value, no digits or too long */
1987 curproxy->url_param_post_limit = str2ui(args[3]);
1988 }
1989 /* if no limit, or faul value in args[3], then default to a moderate wordlen */
1990 if (!curproxy->url_param_post_limit)
1991 curproxy->url_param_post_limit = 48;
1992 else if ( curproxy->url_param_post_limit < 3 )
1993 curproxy->url_param_post_limit = 3; /* minimum example: S=3 or \r\nS=6& */
1994 }
Benoitaffb4812009-03-25 13:02:10 +01001995 }
1996 else if (!strncmp(args[0], "hdr(", 4)) {
1997 const char *beg, *end;
1998
1999 beg = args[0] + 4;
2000 end = strchr(beg, ')');
2001
2002 if (!end || end == beg) {
2003 snprintf(err, errlen, "'balance hdr(name)' requires an http header field name.");
2004 return -1;
2005 }
2006
2007 curproxy->lbprm.algo &= ~BE_LB_ALGO;
2008 curproxy->lbprm.algo |= BE_LB_ALGO_HH;
2009
2010 free(curproxy->hh_name);
2011 curproxy->hh_len = end - beg;
2012 curproxy->hh_name = my_strndup(beg, end - beg);
2013 curproxy->hh_match_domain = 0;
2014
2015 if (*args[1]) {
2016 if (strcmp(args[1], "use_domain_only")) {
2017 snprintf(err, errlen, "'balance hdr(name)' only accepts 'use_domain_only' modifier.");
2018 return -1;
2019 }
2020 curproxy->hh_match_domain = 1;
2021 }
2022
Emeric Brun736aa232009-06-30 17:56:00 +02002023 }
2024 else if (!strncmp(args[0], "rdp-cookie", 10)) {
2025 curproxy->lbprm.algo &= ~BE_LB_ALGO;
2026 curproxy->lbprm.algo |= BE_LB_ALGO_RCH;
2027
2028 if ( *(args[0] + 10 ) == '(' ) { /* cookie name */
2029 const char *beg, *end;
2030
2031 beg = args[0] + 11;
2032 end = strchr(beg, ')');
2033
2034 if (!end || end == beg) {
2035 snprintf(err, errlen, "'balance rdp-cookie(name)' requires an rdp cookie name.");
2036 return -1;
2037 }
2038
2039 free(curproxy->hh_name);
2040 curproxy->hh_name = my_strndup(beg, end - beg);
2041 curproxy->hh_len = end - beg;
2042 }
2043 else if ( *(args[0] + 10 ) == '\0' ) { /* default cookie name 'mstshash' */
2044 free(curproxy->hh_name);
2045 curproxy->hh_name = strdup("mstshash");
2046 curproxy->hh_len = strlen(curproxy->hh_name);
2047 }
2048 else { /* syntax */
2049 snprintf(err, errlen, "'balance rdp-cookie(name)' requires an rdp cookie name.");
2050 return -1;
2051 }
Willy Tarreau01732802007-11-01 22:48:15 +01002052 }
Willy Tarreaua0cbda62007-11-01 21:39:54 +01002053 else {
Emeric Brun736aa232009-06-30 17:56:00 +02002054 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 +01002055 return -1;
2056 }
2057 return 0;
2058}
2059
Willy Tarreaua9d3c1e2007-11-30 20:48:53 +01002060
2061/************************************************************************/
2062/* All supported keywords must be declared here. */
2063/************************************************************************/
2064
2065/* set test->i to the number of enabled servers on the proxy */
2066static int
2067acl_fetch_nbsrv(struct proxy *px, struct session *l4, void *l7, int dir,
2068 struct acl_expr *expr, struct acl_test *test)
2069{
2070 test->flags = ACL_TEST_F_VOL_TEST;
2071 if (expr->arg_len) {
2072 /* another proxy was designated, we must look for it */
2073 for (px = proxy; px; px = px->next)
2074 if ((px->cap & PR_CAP_BE) && !strcmp(px->id, expr->arg.str))
2075 break;
2076 }
2077 if (!px)
2078 return 0;
2079
2080 if (px->srv_act)
2081 test->i = px->srv_act;
2082 else if (px->lbprm.fbck)
2083 test->i = 1;
2084 else
2085 test->i = px->srv_bck;
2086
2087 return 1;
2088}
2089
Jeffrey 'jf' Lim5051d7b2008-09-04 01:03:03 +08002090/* set test->i to the number of enabled servers on the proxy */
2091static int
2092acl_fetch_connslots(struct proxy *px, struct session *l4, void *l7, int dir,
2093 struct acl_expr *expr, struct acl_test *test)
2094{
2095 struct server *iterator;
2096 test->flags = ACL_TEST_F_VOL_TEST;
2097 if (expr->arg_len) {
2098 /* another proxy was designated, we must look for it */
2099 for (px = proxy; px; px = px->next)
2100 if ((px->cap & PR_CAP_BE) && !strcmp(px->id, expr->arg.str))
2101 break;
2102 }
2103 if (!px)
2104 return 0;
2105
2106 test->i = 0;
2107 iterator = px->srv;
2108 while (iterator) {
2109 if ((iterator->state & 1) == 0) {
2110 iterator = iterator->next;
2111 continue;
2112 }
2113 if (iterator->maxconn == 0 || iterator->maxqueue == 0) {
2114 test->i = -1;
2115 return 1;
2116 }
2117
2118 test->i += (iterator->maxconn - iterator->cur_sess)
2119 + (iterator->maxqueue - iterator->nbpend);
2120 iterator = iterator->next;
2121 }
2122
2123 return 1;
2124}
2125
Willy Tarreau079ff0a2009-03-05 21:34:28 +01002126/* set test->i to the number of connections per second reaching the frontend */
2127static int
2128acl_fetch_fe_sess_rate(struct proxy *px, struct session *l4, void *l7, int dir,
2129 struct acl_expr *expr, struct acl_test *test)
2130{
2131 test->flags = ACL_TEST_F_VOL_TEST;
2132 if (expr->arg_len) {
2133 /* another proxy was designated, we must look for it */
2134 for (px = proxy; px; px = px->next)
2135 if ((px->cap & PR_CAP_FE) && !strcmp(px->id, expr->arg.str))
2136 break;
2137 }
2138 if (!px)
2139 return 0;
2140
2141 test->i = read_freq_ctr(&px->fe_sess_per_sec);
2142 return 1;
2143}
2144
2145/* set test->i to the number of connections per second reaching the backend */
2146static int
2147acl_fetch_be_sess_rate(struct proxy *px, struct session *l4, void *l7, int dir,
2148 struct acl_expr *expr, struct acl_test *test)
2149{
2150 test->flags = ACL_TEST_F_VOL_TEST;
2151 if (expr->arg_len) {
2152 /* another proxy was designated, we must look for it */
2153 for (px = proxy; px; px = px->next)
2154 if ((px->cap & PR_CAP_BE) && !strcmp(px->id, expr->arg.str))
2155 break;
2156 }
2157 if (!px)
2158 return 0;
2159
2160 test->i = read_freq_ctr(&px->be_sess_per_sec);
2161 return 1;
2162}
2163
Willy Tarreaua9d3c1e2007-11-30 20:48:53 +01002164
2165/* Note: must not be declared <const> as its list will be overwritten */
2166static struct acl_kw_list acl_kws = {{ },{
Jeffrey 'jf' Lim5051d7b2008-09-04 01:03:03 +08002167 { "nbsrv", acl_parse_int, acl_fetch_nbsrv, acl_match_int, ACL_USE_NOTHING },
Willy Tarreau3a8efeb2009-03-05 19:15:37 +01002168 { "connslots", acl_parse_int, acl_fetch_connslots, acl_match_int, ACL_USE_NOTHING },
Willy Tarreau079ff0a2009-03-05 21:34:28 +01002169 { "fe_sess_rate", acl_parse_int, acl_fetch_fe_sess_rate, acl_match_int, ACL_USE_NOTHING },
2170 { "be_sess_rate", acl_parse_int, acl_fetch_be_sess_rate, acl_match_int, ACL_USE_NOTHING },
Willy Tarreaua9d3c1e2007-11-30 20:48:53 +01002171 { NULL, NULL, NULL, NULL },
2172}};
2173
2174
2175__attribute__((constructor))
2176static void __backend_init(void)
2177{
2178 acl_register_keywords(&acl_kws);
2179}
2180
2181
Willy Tarreaubaaee002006-06-26 02:48:02 +02002182/*
2183 * Local variables:
2184 * c-indent-level: 8
2185 * c-basic-offset: 8
2186 * End:
2187 */