diff options
author | Simon Horman <horms@verge.net.au> | 2010-08-22 08:37:54 -0400 |
---|---|---|
committer | Simon Horman <horms@verge.net.au> | 2010-10-04 09:45:24 -0400 |
commit | 8be67a6617b3403551fccb67b1c624c659419515 (patch) | |
tree | 902f8092ab95dfd06a80bdaf90bb2e51e23f285b /net | |
parent | a3c918acd29a96aba3b46bf50136e7953a480d17 (diff) |
IPVS: management of persistence engine modules
This is based heavily on the scheduler management code
Signed-off-by: Simon Horman <horms@verge.net.au>
Acked-by: Julian Anastasov <ja@ssi.bg>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/ipvs/Makefile | 2 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_pe.c | 147 |
2 files changed, 148 insertions, 1 deletions
diff --git a/net/netfilter/ipvs/Makefile b/net/netfilter/ipvs/Makefile index 349fe8819b89..4a87bf3c6293 100644 --- a/net/netfilter/ipvs/Makefile +++ b/net/netfilter/ipvs/Makefile | |||
@@ -14,7 +14,7 @@ ip_vs-extra_objs-$(CONFIG_IP_VS_NFCT) += ip_vs_nfct.o | |||
14 | 14 | ||
15 | ip_vs-objs := ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o \ | 15 | ip_vs-objs := ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o \ |
16 | ip_vs_xmit.o ip_vs_app.o ip_vs_sync.o \ | 16 | ip_vs_xmit.o ip_vs_app.o ip_vs_sync.o \ |
17 | ip_vs_est.o ip_vs_proto.o \ | 17 | ip_vs_est.o ip_vs_proto.o ip_vs_pe.o \ |
18 | $(ip_vs_proto-objs-y) $(ip_vs-extra_objs-y) | 18 | $(ip_vs_proto-objs-y) $(ip_vs-extra_objs-y) |
19 | 19 | ||
20 | 20 | ||
diff --git a/net/netfilter/ipvs/ip_vs_pe.c b/net/netfilter/ipvs/ip_vs_pe.c new file mode 100644 index 000000000000..3414af70ee12 --- /dev/null +++ b/net/netfilter/ipvs/ip_vs_pe.c | |||
@@ -0,0 +1,147 @@ | |||
1 | #define KMSG_COMPONENT "IPVS" | ||
2 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
3 | |||
4 | #include <linux/module.h> | ||
5 | #include <linux/spinlock.h> | ||
6 | #include <linux/interrupt.h> | ||
7 | #include <asm/string.h> | ||
8 | #include <linux/kmod.h> | ||
9 | #include <linux/sysctl.h> | ||
10 | |||
11 | #include <net/ip_vs.h> | ||
12 | |||
13 | /* IPVS pe list */ | ||
14 | static LIST_HEAD(ip_vs_pe); | ||
15 | |||
16 | /* lock for service table */ | ||
17 | static DEFINE_SPINLOCK(ip_vs_pe_lock); | ||
18 | |||
19 | /* Bind a service with a pe */ | ||
20 | void ip_vs_bind_pe(struct ip_vs_service *svc, struct ip_vs_pe *pe) | ||
21 | { | ||
22 | svc->pe = pe; | ||
23 | } | ||
24 | |||
25 | /* Unbind a service from its pe */ | ||
26 | void ip_vs_unbind_pe(struct ip_vs_service *svc) | ||
27 | { | ||
28 | svc->pe = NULL; | ||
29 | } | ||
30 | |||
31 | /* Get pe in the pe list by name */ | ||
32 | static struct ip_vs_pe * | ||
33 | ip_vs_pe_getbyname(const char *pe_name) | ||
34 | { | ||
35 | struct ip_vs_pe *pe; | ||
36 | |||
37 | IP_VS_DBG(2, "%s(): pe_name \"%s\"\n", __func__, | ||
38 | pe_name); | ||
39 | |||
40 | spin_lock_bh(&ip_vs_pe_lock); | ||
41 | |||
42 | list_for_each_entry(pe, &ip_vs_pe, n_list) { | ||
43 | /* Test and get the modules atomically */ | ||
44 | if (pe->module && | ||
45 | !try_module_get(pe->module)) { | ||
46 | /* This pe is just deleted */ | ||
47 | continue; | ||
48 | } | ||
49 | if (strcmp(pe_name, pe->name)==0) { | ||
50 | /* HIT */ | ||
51 | spin_unlock_bh(&ip_vs_pe_lock); | ||
52 | return pe; | ||
53 | } | ||
54 | if (pe->module) | ||
55 | module_put(pe->module); | ||
56 | } | ||
57 | |||
58 | spin_unlock_bh(&ip_vs_pe_lock); | ||
59 | return NULL; | ||
60 | } | ||
61 | |||
62 | /* Lookup pe and try to load it if it doesn't exist */ | ||
63 | struct ip_vs_pe *ip_vs_pe_get(const char *name) | ||
64 | { | ||
65 | struct ip_vs_pe *pe; | ||
66 | |||
67 | /* Search for the pe by name */ | ||
68 | pe = ip_vs_pe_getbyname(name); | ||
69 | |||
70 | /* If pe not found, load the module and search again */ | ||
71 | if (!pe) { | ||
72 | request_module("ip_vs_pe_%s", name); | ||
73 | pe = ip_vs_pe_getbyname(name); | ||
74 | } | ||
75 | |||
76 | return pe; | ||
77 | } | ||
78 | |||
79 | void ip_vs_pe_put(struct ip_vs_pe *pe) | ||
80 | { | ||
81 | if (pe && pe->module) | ||
82 | module_put(pe->module); | ||
83 | } | ||
84 | |||
85 | /* Register a pe in the pe list */ | ||
86 | int register_ip_vs_pe(struct ip_vs_pe *pe) | ||
87 | { | ||
88 | struct ip_vs_pe *tmp; | ||
89 | |||
90 | /* increase the module use count */ | ||
91 | ip_vs_use_count_inc(); | ||
92 | |||
93 | spin_lock_bh(&ip_vs_pe_lock); | ||
94 | |||
95 | if (!list_empty(&pe->n_list)) { | ||
96 | spin_unlock_bh(&ip_vs_pe_lock); | ||
97 | ip_vs_use_count_dec(); | ||
98 | pr_err("%s(): [%s] pe already linked\n", | ||
99 | __func__, pe->name); | ||
100 | return -EINVAL; | ||
101 | } | ||
102 | |||
103 | /* Make sure that the pe with this name doesn't exist | ||
104 | * in the pe list. | ||
105 | */ | ||
106 | list_for_each_entry(tmp, &ip_vs_pe, n_list) { | ||
107 | if (strcmp(tmp->name, pe->name) == 0) { | ||
108 | spin_unlock_bh(&ip_vs_pe_lock); | ||
109 | ip_vs_use_count_dec(); | ||
110 | pr_err("%s(): [%s] pe already existed " | ||
111 | "in the system\n", __func__, pe->name); | ||
112 | return -EINVAL; | ||
113 | } | ||
114 | } | ||
115 | /* Add it into the d-linked pe list */ | ||
116 | list_add(&pe->n_list, &ip_vs_pe); | ||
117 | spin_unlock_bh(&ip_vs_pe_lock); | ||
118 | |||
119 | pr_info("[%s] pe registered.\n", pe->name); | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | EXPORT_SYMBOL_GPL(register_ip_vs_pe); | ||
124 | |||
125 | /* Unregister a pe from the pe list */ | ||
126 | int unregister_ip_vs_pe(struct ip_vs_pe *pe) | ||
127 | { | ||
128 | spin_lock_bh(&ip_vs_pe_lock); | ||
129 | if (list_empty(&pe->n_list)) { | ||
130 | spin_unlock_bh(&ip_vs_pe_lock); | ||
131 | pr_err("%s(): [%s] pe is not in the list. failed\n", | ||
132 | __func__, pe->name); | ||
133 | return -EINVAL; | ||
134 | } | ||
135 | |||
136 | /* Remove it from the d-linked pe list */ | ||
137 | list_del(&pe->n_list); | ||
138 | spin_unlock_bh(&ip_vs_pe_lock); | ||
139 | |||
140 | /* decrease the module use count */ | ||
141 | ip_vs_use_count_dec(); | ||
142 | |||
143 | pr_info("[%s] pe unregistered.\n", pe->name); | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | EXPORT_SYMBOL_GPL(unregister_ip_vs_pe); | ||