Linux-libre 3.7.6-gnu1
[librecmc/linux-libre.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  *      Weighted Least Connection scheduling
32  */
33 static struct ip_vs_dest *
34 ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
35 {
36         struct ip_vs_dest *dest, *least;
37         unsigned int loh, doh;
38
39         IP_VS_DBG(6, "ip_vs_wlc_schedule(): Scheduling...\n");
40
41         /*
42          * We calculate the load of each dest server as follows:
43          *                (dest overhead) / dest->weight
44          *
45          * Remember -- no floats in kernel mode!!!
46          * The comparison of h1*w2 > h2*w1 is equivalent to that of
47          *                h1/w1 > h2/w2
48          * if every weight is larger than zero.
49          *
50          * The server with weight=0 is quiesced and will not receive any
51          * new connections.
52          */
53
54         list_for_each_entry(dest, &svc->destinations, n_list) {
55                 if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
56                     atomic_read(&dest->weight) > 0) {
57                         least = dest;
58                         loh = ip_vs_dest_conn_overhead(least);
59                         goto nextstage;
60                 }
61         }
62         ip_vs_scheduler_err(svc, "no destination available");
63         return NULL;
64
65         /*
66          *    Find the destination with the least load.
67          */
68   nextstage:
69         list_for_each_entry_continue(dest, &svc->destinations, n_list) {
70                 if (dest->flags & IP_VS_DEST_F_OVERLOAD)
71                         continue;
72                 doh = ip_vs_dest_conn_overhead(dest);
73                 if (loh * atomic_read(&dest->weight) >
74                     doh * atomic_read(&least->weight)) {
75                         least = dest;
76                         loh = doh;
77                 }
78         }
79
80         IP_VS_DBG_BUF(6, "WLC: server %s:%u "
81                       "activeconns %d refcnt %d weight %d overhead %d\n",
82                       IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port),
83                       atomic_read(&least->activeconns),
84                       atomic_read(&least->refcnt),
85                       atomic_read(&least->weight), loh);
86
87         return least;
88 }
89
90
91 static struct ip_vs_scheduler ip_vs_wlc_scheduler =
92 {
93         .name =                 "wlc",
94         .refcnt =               ATOMIC_INIT(0),
95         .module =               THIS_MODULE,
96         .n_list =               LIST_HEAD_INIT(ip_vs_wlc_scheduler.n_list),
97         .schedule =             ip_vs_wlc_schedule,
98 };
99
100
101 static int __init ip_vs_wlc_init(void)
102 {
103         return register_ip_vs_scheduler(&ip_vs_wlc_scheduler);
104 }
105
106 static void __exit ip_vs_wlc_cleanup(void)
107 {
108         unregister_ip_vs_scheduler(&ip_vs_wlc_scheduler);
109 }
110
111 module_init(ip_vs_wlc_init);
112 module_exit(ip_vs_wlc_cleanup);
113 MODULE_LICENSE("GPL");