1616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis/*
2616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis * IPVS:        Weighted Fail Over module
3616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis *
4616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis * Authors:     Kenny Mathis <kmathis@chokepoint.net>
5616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis *
6616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis *              This program is free software; you can redistribute it and/or
7616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis *              modify it under the terms of the GNU General Public License
8616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis *              as published by the Free Software Foundation; either version
9616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis *              2 of the License, or (at your option) any later version.
10616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis *
11616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis * Changes:
12616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis *     Kenny Mathis            :     added initial functionality based on weight
13616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis *
14616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis */
15616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis
16616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis#define KMSG_COMPONENT "IPVS"
17616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
18616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis
19616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis#include <linux/module.h>
20616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis#include <linux/kernel.h>
21616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis
22616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis#include <net/ip_vs.h>
23616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis
24616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis/* Weighted Fail Over Module */
25616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathisstatic struct ip_vs_dest *
26616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathisip_vs_fo_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
27616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis		  struct ip_vs_iphdr *iph)
28616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis{
29616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	struct ip_vs_dest *dest, *hweight = NULL;
30616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	int hw = 0; /* Track highest weight */
31616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis
32616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	IP_VS_DBG(6, "ip_vs_fo_schedule(): Scheduling...\n");
33616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis
34616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	/* Basic failover functionality
35616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	 * Find virtual server with highest weight and send it traffic
36616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	 */
37616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
38616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis		if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
39616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis		    atomic_read(&dest->weight) > hw) {
40616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis			hweight = dest;
41616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis			hw = atomic_read(&dest->weight);
42616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis		}
43616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	}
44616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis
45616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	if (hweight) {
46616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis		IP_VS_DBG_BUF(6, "FO: server %s:%u activeconns %d weight %d\n",
474d316f3f9ae3d5fad8d3198eec0a4ef2511471d7Julian Anastasov			      IP_VS_DBG_ADDR(hweight->af, &hweight->addr),
48616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis			      ntohs(hweight->port),
49616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis			      atomic_read(&hweight->activeconns),
50616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis			      atomic_read(&hweight->weight));
51616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis		return hweight;
52616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	}
53616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis
54616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	ip_vs_scheduler_err(svc, "no destination available");
55616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	return NULL;
56616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis}
57616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis
58616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathisstatic struct ip_vs_scheduler ip_vs_fo_scheduler = {
59616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	.name =			"fo",
60616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	.refcnt =		ATOMIC_INIT(0),
61616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	.module =		THIS_MODULE,
62616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	.n_list =		LIST_HEAD_INIT(ip_vs_fo_scheduler.n_list),
63616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	.schedule =		ip_vs_fo_schedule,
64616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis};
65616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis
66616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathisstatic int __init ip_vs_fo_init(void)
67616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis{
68616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	return register_ip_vs_scheduler(&ip_vs_fo_scheduler);
69616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis}
70616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis
71616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathisstatic void __exit ip_vs_fo_cleanup(void)
72616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis{
73616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	unregister_ip_vs_scheduler(&ip_vs_fo_scheduler);
74616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis	synchronize_rcu();
75616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis}
76616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathis
77616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathismodule_init(ip_vs_fo_init);
78616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny Mathismodule_exit(ip_vs_fo_cleanup);
79616a9be25cb9516e546c0de55d61e1e46e54ade9Kenny MathisMODULE_LICENSE("GPL");
80