/* * KTCPVS An implementation of the TCP Virtual Server daemon inside * kernel for the LINUX operating system. KTCPVS can be used * to build a moderately scalable and highly available server * based on a cluster of servers, with more flexibility. * * Version: $Id$ * * Authors: Wensong Zhang * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * */ #include #include #ifdef CONFIG_KMOD #include #endif #include #include #include #include #include #include "tcp_vs.h" static int tcp_vs_wlc_init_vs (struct tcp_vs *vs) { MOD_INC_USE_COUNT; return 0; } static int tcp_vs_wlc_done_vs (struct tcp_vs *vs) { MOD_DEC_USE_COUNT; return 0; } static int tcp_vs_wlc_update_vs (struct tcp_vs *vs) { return 0; } /* * Weighted Least Connection scheduling */ static struct socket *tcp_vs_wlc_schedule(struct tcp_vs_conn *conn, struct tcp_vs *vs) { register struct list_head *l, *e; struct tcp_vs_dest *dest, *least; TCP_VS_DBG ("tcp_vs_wlc_schedule(): Scheduling...\n"); /* * We use the following formula to estimate the overhead: * dest->conns / dest->weight * * Remember -- no floats in kernel mode!!! * The comparison of h1*w2 > h2*w1 is equivalent to that of * h1/w1 > h2/w2 * when each weight is larger than zero. * * The server with weight=0 is quiesced and will not receive any * new connection. */ l = &vs->destinations; for (e=l->next; e!=l; e=e->next) { least = list_entry (e, struct tcp_vs_dest, n_list); if (least->weight > 0) { goto nextstage; } } return NULL; /* * Find the destination with the least load. */ nextstage: for (e=e->next; e!=l; e=e->next) { dest = list_entry (e, struct tcp_vs_dest, n_list); if (atomic_read(&least->conns)*dest->weight > atomic_read(&dest->conns)*least->weight) { least = dest; } } TCP_VS_DBG ("WLC: server %d.%d.%d.%d:%d " "conns %d refcnt %d weight %d\n", NIPQUAD(least->addr), ntohs(least->port), atomic_read(&least->conns), atomic_read (&least->refcnt), least->weight); atomic_inc(&least->conns); conn->dest = least; conn->dsock = tcp_vs_connect2dest(least); return conn->dsock; } static struct tcp_vs_scheduler tcp_vs_wlc_scheduler = { {0}, /* n_list */ "wlc", /* name */ ATOMIC_INIT (0), /* refcnt */ tcp_vs_wlc_init_vs, /* initializer */ tcp_vs_wlc_done_vs, /* done */ tcp_vs_wlc_update_vs, /* update */ NULL, /* control */ tcp_vs_wlc_schedule, /* select a server from the destination list */ }; #ifdef MODULE int tcp_vs_wlc_init (void) #else int __init tcp_vs_wlc_init (void) #endif { TCP_VS_INFO ("Initializing WLC scheduling\n"); INIT_LIST_HEAD (&tcp_vs_wlc_scheduler.n_list); return register_tcp_vs_scheduler (&tcp_vs_wlc_scheduler); } #ifdef MODULE EXPORT_NO_SYMBOLS; int init_module (void) { if (tcp_vs_wlc_init() != 0) return -EIO; TCP_VS_INFO ("WLC scheduling module loaded.\n"); return 0; } void cleanup_module (void) { /* module cleanup by 'release_module' */ if (unregister_tcp_vs_scheduler (&tcp_vs_wlc_scheduler) != 0) TCP_VS_INFO ("cannot remove WLC scheduling module\n"); else TCP_VS_INFO ("WLC scheduling module unloaded.\n"); } #endif /* MODULE */