aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorSimon Horman <horms@verge.net.au>2010-08-22 08:37:54 -0400
committerSimon Horman <horms@verge.net.au>2010-10-04 09:45:24 -0400
commit8be67a6617b3403551fccb67b1c624c659419515 (patch)
tree902f8092ab95dfd06a80bdaf90bb2e51e23f285b /net
parenta3c918acd29a96aba3b46bf50136e7953a480d17 (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/Makefile2
-rw-r--r--net/netfilter/ipvs/ip_vs_pe.c147
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
15ip_vs-objs := ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o \ 15ip_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 */
14static LIST_HEAD(ip_vs_pe);
15
16/* lock for service table */
17static DEFINE_SPINLOCK(ip_vs_pe_lock);
18
19/* Bind a service with a pe */
20void 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 */
26void 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 */
32static struct ip_vs_pe *
33ip_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 */
63struct 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
79void 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 */
86int 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}
123EXPORT_SYMBOL_GPL(register_ip_vs_pe);
124
125/* Unregister a pe from the pe list */
126int 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}
147EXPORT_SYMBOL_GPL(unregister_ip_vs_pe);