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 * |
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(v: &dest->weight) > hw) { |
35 | hweight = dest; |
36 | hw = atomic_read(v: &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, msg: "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 | |
61 | static int __init ip_vs_fo_init(void) |
62 | { |
63 | return register_ip_vs_scheduler(scheduler: &ip_vs_fo_scheduler); |
64 | } |
65 | |
66 | static void __exit ip_vs_fo_cleanup(void) |
67 | { |
68 | unregister_ip_vs_scheduler(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 | MODULE_DESCRIPTION("ipvs weighted failover scheduler" ); |
76 | |