Merge branch 'for-linus' of git://www.jni.nu/cris
[deliverable/linux.git] / net / netfilter / ipvs / ip_vs_wlc.c
1 /*
2 * IPVS: Weighted Least-Connection Scheduling module
3 *
4 * Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
5 * Peter Kese <peter.kese@ijs.si>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * Changes:
13 * Wensong Zhang : changed the ip_vs_wlc_schedule to return dest
14 * Wensong Zhang : changed to use the inactconns in scheduling
15 * Wensong Zhang : changed some comestics things for debugging
16 * Wensong Zhang : changed for the d-linked destination list
17 * Wensong Zhang : added the ip_vs_wlc_update_svc
18 * Wensong Zhang : added any dest with weight=0 is quiesced
19 *
20 */
21
22 #define KMSG_COMPONENT "IPVS"
23 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
24
25 #include <linux/module.h>
26 #include <linux/kernel.h>
27
28 #include <net/ip_vs.h>
29
30
31 static inline unsigned int
32 ip_vs_wlc_dest_overhead(struct ip_vs_dest *dest)
33 {
34 /*
35 * We think the overhead of processing active connections is 256
36 * times higher than that of inactive connections in average. (This
37 * 256 times might not be accurate, we will change it later) We
38 * use the following formula to estimate the overhead now:
39 * dest->activeconns*256 + dest->inactconns
40 */
41 return (atomic_read(&dest->activeconns) << 8) +
42 atomic_read(&dest->inactconns);
43 }
44
45
46 /*
47 * Weighted Least Connection scheduling
48 */
49 static struct ip_vs_dest *
50 ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
51 {
52 struct ip_vs_dest *dest, *least;
53 unsigned int loh, doh;
54
55 IP_VS_DBG(6, "ip_vs_wlc_schedule(): Scheduling...\n");
56
57 /*
58 * We calculate the load of each dest server as follows:
59 * (dest overhead) / dest->weight
60 *
61 * Remember -- no floats in kernel mode!!!
62 * The comparison of h1*w2 > h2*w1 is equivalent to that of
63 * h1/w1 > h2/w2
64 * if every weight is larger than zero.
65 *
66 * The server with weight=0 is quiesced and will not receive any
67 * new connections.
68 */
69
70 list_for_each_entry(dest, &svc->destinations, n_list) {
71 if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
72 atomic_read(&dest->weight) > 0) {
73 least = dest;
74 loh = ip_vs_wlc_dest_overhead(least);
75 goto nextstage;
76 }
77 }
78 IP_VS_ERR_RL("WLC: no destination available\n");
79 return NULL;
80
81 /*
82 * Find the destination with the least load.
83 */
84 nextstage:
85 list_for_each_entry_continue(dest, &svc->destinations, n_list) {
86 if (dest->flags & IP_VS_DEST_F_OVERLOAD)
87 continue;
88 doh = ip_vs_wlc_dest_overhead(dest);
89 if (loh * atomic_read(&dest->weight) >
90 doh * atomic_read(&least->weight)) {
91 least = dest;
92 loh = doh;
93 }
94 }
95
96 IP_VS_DBG_BUF(6, "WLC: server %s:%u "
97 "activeconns %d refcnt %d weight %d overhead %d\n",
98 IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port),
99 atomic_read(&least->activeconns),
100 atomic_read(&least->refcnt),
101 atomic_read(&least->weight), loh);
102
103 return least;
104 }
105
106
107 static struct ip_vs_scheduler ip_vs_wlc_scheduler =
108 {
109 .name = "wlc",
110 .refcnt = ATOMIC_INIT(0),
111 .module = THIS_MODULE,
112 .n_list = LIST_HEAD_INIT(ip_vs_wlc_scheduler.n_list),
113 .schedule = ip_vs_wlc_schedule,
114 };
115
116
117 static int __init ip_vs_wlc_init(void)
118 {
119 return register_ip_vs_scheduler(&ip_vs_wlc_scheduler);
120 }
121
122 static void __exit ip_vs_wlc_cleanup(void)
123 {
124 unregister_ip_vs_scheduler(&ip_vs_wlc_scheduler);
125 }
126
127 module_init(ip_vs_wlc_init);
128 module_exit(ip_vs_wlc_cleanup);
129 MODULE_LICENSE("GPL");
This page took 0.040289 seconds and 5 git commands to generate.