Commit | Line | Data |
---|---|---|
8be67a66 SH |
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 | ||
60b6aa3b JA |
16 | /* semaphore for IPVS PEs. */ |
17 | static DEFINE_MUTEX(ip_vs_pe_mutex); | |
8be67a66 | 18 | |
8be67a66 | 19 | /* Get pe in the pe list by name */ |
fe5e7a1e | 20 | struct ip_vs_pe *__ip_vs_pe_getbyname(const char *pe_name) |
8be67a66 SH |
21 | { |
22 | struct ip_vs_pe *pe; | |
23 | ||
fe5e7a1e | 24 | IP_VS_DBG(10, "%s(): pe_name \"%s\"\n", __func__, |
8be67a66 SH |
25 | pe_name); |
26 | ||
60b6aa3b JA |
27 | rcu_read_lock(); |
28 | list_for_each_entry_rcu(pe, &ip_vs_pe, n_list) { | |
8be67a66 SH |
29 | /* Test and get the modules atomically */ |
30 | if (pe->module && | |
31 | !try_module_get(pe->module)) { | |
32 | /* This pe is just deleted */ | |
33 | continue; | |
34 | } | |
35 | if (strcmp(pe_name, pe->name)==0) { | |
36 | /* HIT */ | |
60b6aa3b | 37 | rcu_read_unlock(); |
8be67a66 SH |
38 | return pe; |
39 | } | |
982f4051 | 40 | module_put(pe->module); |
8be67a66 | 41 | } |
60b6aa3b | 42 | rcu_read_unlock(); |
8be67a66 | 43 | |
8be67a66 SH |
44 | return NULL; |
45 | } | |
46 | ||
47 | /* Lookup pe and try to load it if it doesn't exist */ | |
e9e5eee8 | 48 | struct ip_vs_pe *ip_vs_pe_getbyname(const char *name) |
8be67a66 SH |
49 | { |
50 | struct ip_vs_pe *pe; | |
51 | ||
52 | /* Search for the pe by name */ | |
e9e5eee8 | 53 | pe = __ip_vs_pe_getbyname(name); |
8be67a66 SH |
54 | |
55 | /* If pe not found, load the module and search again */ | |
56 | if (!pe) { | |
57 | request_module("ip_vs_pe_%s", name); | |
e9e5eee8 | 58 | pe = __ip_vs_pe_getbyname(name); |
8be67a66 SH |
59 | } |
60 | ||
61 | return pe; | |
62 | } | |
63 | ||
8be67a66 SH |
64 | /* Register a pe in the pe list */ |
65 | int register_ip_vs_pe(struct ip_vs_pe *pe) | |
66 | { | |
67 | struct ip_vs_pe *tmp; | |
68 | ||
69 | /* increase the module use count */ | |
70 | ip_vs_use_count_inc(); | |
71 | ||
60b6aa3b | 72 | mutex_lock(&ip_vs_pe_mutex); |
8be67a66 SH |
73 | /* Make sure that the pe with this name doesn't exist |
74 | * in the pe list. | |
75 | */ | |
76 | list_for_each_entry(tmp, &ip_vs_pe, n_list) { | |
77 | if (strcmp(tmp->name, pe->name) == 0) { | |
60b6aa3b | 78 | mutex_unlock(&ip_vs_pe_mutex); |
8be67a66 SH |
79 | ip_vs_use_count_dec(); |
80 | pr_err("%s(): [%s] pe already existed " | |
81 | "in the system\n", __func__, pe->name); | |
82 | return -EINVAL; | |
83 | } | |
84 | } | |
85 | /* Add it into the d-linked pe list */ | |
60b6aa3b JA |
86 | list_add_rcu(&pe->n_list, &ip_vs_pe); |
87 | mutex_unlock(&ip_vs_pe_mutex); | |
8be67a66 SH |
88 | |
89 | pr_info("[%s] pe registered.\n", pe->name); | |
90 | ||
91 | return 0; | |
92 | } | |
93 | EXPORT_SYMBOL_GPL(register_ip_vs_pe); | |
94 | ||
95 | /* Unregister a pe from the pe list */ | |
96 | int unregister_ip_vs_pe(struct ip_vs_pe *pe) | |
97 | { | |
60b6aa3b | 98 | mutex_lock(&ip_vs_pe_mutex); |
8be67a66 | 99 | /* Remove it from the d-linked pe list */ |
60b6aa3b JA |
100 | list_del_rcu(&pe->n_list); |
101 | mutex_unlock(&ip_vs_pe_mutex); | |
8be67a66 SH |
102 | |
103 | /* decrease the module use count */ | |
104 | ip_vs_use_count_dec(); | |
105 | ||
106 | pr_info("[%s] pe unregistered.\n", pe->name); | |
107 | ||
108 | return 0; | |
109 | } | |
110 | EXPORT_SYMBOL_GPL(unregister_ip_vs_pe); |