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