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