xref: /openbmc/linux/net/netfilter/ipvs/ip_vs_fo.c (revision 2874c5fd)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * IPVS:        Weighted Fail Over module
4  *
5  * Authors:     Kenny Mathis <kmathis@chokepoint.net>
6  *
7  * Changes:
8  *     Kenny Mathis            :     added initial functionality based on weight
9  */
10 
11 #define KMSG_COMPONENT "IPVS"
12 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
13 
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 
17 #include <net/ip_vs.h>
18 
19 /* Weighted Fail Over Module */
20 static struct ip_vs_dest *
ip_vs_fo_schedule(struct ip_vs_service * svc,const struct sk_buff * skb,struct ip_vs_iphdr * iph)21 ip_vs_fo_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
22 		  struct ip_vs_iphdr *iph)
23 {
24 	struct ip_vs_dest *dest, *hweight = NULL;
25 	int hw = 0; /* Track highest weight */
26 
27 	IP_VS_DBG(6, "ip_vs_fo_schedule(): Scheduling...\n");
28 
29 	/* Basic failover functionality
30 	 * Find virtual server with highest weight and send it traffic
31 	 */
32 	list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
33 		if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
34 		    atomic_read(&dest->weight) > hw) {
35 			hweight = dest;
36 			hw = atomic_read(&dest->weight);
37 		}
38 	}
39 
40 	if (hweight) {
41 		IP_VS_DBG_BUF(6, "FO: server %s:%u activeconns %d weight %d\n",
42 			      IP_VS_DBG_ADDR(hweight->af, &hweight->addr),
43 			      ntohs(hweight->port),
44 			      atomic_read(&hweight->activeconns),
45 			      atomic_read(&hweight->weight));
46 		return hweight;
47 	}
48 
49 	ip_vs_scheduler_err(svc, "no destination available");
50 	return NULL;
51 }
52 
53 static struct ip_vs_scheduler ip_vs_fo_scheduler = {
54 	.name =			"fo",
55 	.refcnt =		ATOMIC_INIT(0),
56 	.module =		THIS_MODULE,
57 	.n_list =		LIST_HEAD_INIT(ip_vs_fo_scheduler.n_list),
58 	.schedule =		ip_vs_fo_schedule,
59 };
60 
ip_vs_fo_init(void)61 static int __init ip_vs_fo_init(void)
62 {
63 	return register_ip_vs_scheduler(&ip_vs_fo_scheduler);
64 }
65 
ip_vs_fo_cleanup(void)66 static void __exit ip_vs_fo_cleanup(void)
67 {
68 	unregister_ip_vs_scheduler(&ip_vs_fo_scheduler);
69 	synchronize_rcu();
70 }
71 
72 module_init(ip_vs_fo_init);
73 module_exit(ip_vs_fo_cleanup);
74 MODULE_LICENSE("GPL");
75