Blame view
net/netfilter/ipvs/ip_vs_conn.c
36.2 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 |
/* * IPVS An implementation of the IP virtual server support for the * LINUX operating system. IPVS is now implemented as a module * over the Netfilter framework. IPVS can be used to build a * high-performance and highly available server based on a * cluster of servers. * |
1da177e4c Linux-2.6.12-rc2 |
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org> * Peter Kese <peter.kese@ijs.si> * Julian Anastasov <ja@ssi.bg> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * The IPVS code for kernel 2.2 was done by Wensong Zhang and Peter Kese, * with changes/fixes from Julian Anastasov, Lars Marowsky-Bree, Horms * and others. Many code here is taken from IP MASQ code of kernel 2.2. * * Changes: * */ |
9aada7ac0 IPVS: use pr_fmt |
24 25 |
#define KMSG_COMPONENT "IPVS" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
e924283bf [IPVS]: Another f... |
26 |
#include <linux/interrupt.h> |
14c850212 [INET_SOCK]: Move... |
27 |
#include <linux/in.h> |
f18ae7206 ipvs: use the new... |
28 |
#include <linux/inet.h> |
f190055ff [IPVS]: Add missi... |
29 |
#include <linux/net.h> |
1da177e4c Linux-2.6.12-rc2 |
30 |
#include <linux/kernel.h> |
14c850212 [INET_SOCK]: Move... |
31 |
#include <linux/module.h> |
1da177e4c Linux-2.6.12-rc2 |
32 33 |
#include <linux/vmalloc.h> #include <linux/proc_fs.h> /* for proc_net_* */ |
5a0e3ad6a include cleanup: ... |
34 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
35 36 37 |
#include <linux/seq_file.h> #include <linux/jhash.h> #include <linux/random.h> |
457c4cbc5 [NET]: Make /proc... |
38 |
#include <net/net_namespace.h> |
1da177e4c Linux-2.6.12-rc2 |
39 |
#include <net/ip_vs.h> |
6f7edb488 IPVS: Allow boot ... |
40 41 42 43 44 45 46 |
#ifndef CONFIG_IP_VS_TAB_BITS #define CONFIG_IP_VS_TAB_BITS 12 #endif /* * Connection hash size. Default is what was selected at compile time. */ |
4ecd29447 ipvs: add static ... |
47 |
static int ip_vs_conn_tab_bits = CONFIG_IP_VS_TAB_BITS; |
6f7edb488 IPVS: Allow boot ... |
48 49 50 51 |
module_param_named(conn_tab_bits, ip_vs_conn_tab_bits, int, 0444); MODULE_PARM_DESC(conn_tab_bits, "Set connections' hash size"); /* size and mask values */ |
4ecd29447 ipvs: add static ... |
52 53 |
int ip_vs_conn_tab_size __read_mostly; static int ip_vs_conn_tab_mask __read_mostly; |
6f7edb488 IPVS: Allow boot ... |
54 |
|
1da177e4c Linux-2.6.12-rc2 |
55 56 57 |
/* * Connection hash table: for input and output packets lookups of IPVS */ |
731109e78 ipvs: use hlist i... |
58 |
static struct hlist_head *ip_vs_conn_tab __read_mostly; |
1da177e4c Linux-2.6.12-rc2 |
59 60 |
/* SLAB cache for IPVS connections */ |
e18b890bb [PATCH] slab: rem... |
61 |
static struct kmem_cache *ip_vs_conn_cachep __read_mostly; |
1da177e4c Linux-2.6.12-rc2 |
62 |
|
1da177e4c Linux-2.6.12-rc2 |
63 64 65 66 |
/* counter for no client port connections */ static atomic_t ip_vs_conn_no_cport_cnt = ATOMIC_INIT(0); /* random value for IPVS connection hash */ |
4ecd29447 ipvs: add static ... |
67 |
static unsigned int ip_vs_conn_rnd __read_mostly; |
1da177e4c Linux-2.6.12-rc2 |
68 69 70 71 |
/* * Fine locking granularity for big connection hash table */ |
6e67e586e IPVS: netns, conn... |
72 |
#define CT_LOCKARRAY_BITS 5 |
1da177e4c Linux-2.6.12-rc2 |
73 74 |
#define CT_LOCKARRAY_SIZE (1<<CT_LOCKARRAY_BITS) #define CT_LOCKARRAY_MASK (CT_LOCKARRAY_SIZE-1) |
f18ae7206 ipvs: use the new... |
75 76 77 78 79 80 |
/* We need an addrstrlen that works with or without v6 */ #ifdef CONFIG_IP_VS_IPV6 #define IP_VS_ADDRSTRLEN INET6_ADDRSTRLEN #else #define IP_VS_ADDRSTRLEN (8+1) #endif |
1da177e4c Linux-2.6.12-rc2 |
81 82 |
struct ip_vs_aligned_lock { |
088339a57 ipvs: convert con... |
83 |
spinlock_t l; |
1da177e4c Linux-2.6.12-rc2 |
84 85 86 87 88 |
} __attribute__((__aligned__(SMP_CACHE_BYTES))); /* lock array for conn table */ static struct ip_vs_aligned_lock __ip_vs_conntbl_lock_array[CT_LOCKARRAY_SIZE] __cacheline_aligned; |
ac69269a4 ipvs: do not disa... |
89 |
static inline void ct_write_lock_bh(unsigned int key) |
1da177e4c Linux-2.6.12-rc2 |
90 |
{ |
ac69269a4 ipvs: do not disa... |
91 |
spin_lock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l); |
1da177e4c Linux-2.6.12-rc2 |
92 |
} |
ac69269a4 ipvs: do not disa... |
93 |
static inline void ct_write_unlock_bh(unsigned int key) |
1da177e4c Linux-2.6.12-rc2 |
94 |
{ |
ac69269a4 ipvs: do not disa... |
95 |
spin_unlock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l); |
1da177e4c Linux-2.6.12-rc2 |
96 |
} |
013b04246 ipvs: optimize re... |
97 |
static void ip_vs_conn_expire(unsigned long data); |
1da177e4c Linux-2.6.12-rc2 |
98 99 100 101 |
/* * Returns hash value for IPVS connection entry */ |
754b81a35 ipvs: Pass ipvs n... |
102 |
static unsigned int ip_vs_conn_hashkey(struct netns_ipvs *ipvs, int af, unsigned int proto, |
28364a59f IPVS: Extend func... |
103 104 |
const union nf_inet_addr *addr, __be16 port) |
1da177e4c Linux-2.6.12-rc2 |
105 |
{ |
28364a59f IPVS: Extend func... |
106 107 |
#ifdef CONFIG_IP_VS_IPV6 if (af == AF_INET6) |
6e67e586e IPVS: netns, conn... |
108 109 |
return (jhash_3words(jhash(addr, 16, ip_vs_conn_rnd), (__force u32)port, proto, ip_vs_conn_rnd) ^ |
754b81a35 ipvs: Pass ipvs n... |
110 |
((size_t)ipvs>>8)) & ip_vs_conn_tab_mask; |
28364a59f IPVS: Extend func... |
111 |
#endif |
6e67e586e IPVS: netns, conn... |
112 113 |
return (jhash_3words((__force u32)addr->ip, (__force u32)port, proto, ip_vs_conn_rnd) ^ |
754b81a35 ipvs: Pass ipvs n... |
114 |
((size_t)ipvs>>8)) & ip_vs_conn_tab_mask; |
1da177e4c Linux-2.6.12-rc2 |
115 |
} |
85999283a IPVS: Add struct ... |
116 117 118 119 120 |
static unsigned int ip_vs_conn_hashkey_param(const struct ip_vs_conn_param *p, bool inverse) { const union nf_inet_addr *addr; __be16 port; |
f71499aa1 IPVS: Fallback if... |
121 |
if (p->pe_data && p->pe->hashkey_raw) |
85999283a IPVS: Add struct ... |
122 123 124 125 126 127 128 129 130 131 |
return p->pe->hashkey_raw(p, ip_vs_conn_rnd, inverse) & ip_vs_conn_tab_mask; if (likely(!inverse)) { addr = p->caddr; port = p->cport; } else { addr = p->vaddr; port = p->vport; } |
754b81a35 ipvs: Pass ipvs n... |
132 |
return ip_vs_conn_hashkey(p->ipvs, p->af, p->protocol, addr, port); |
85999283a IPVS: Add struct ... |
133 134 135 136 137 |
} static unsigned int ip_vs_conn_hashkey_conn(const struct ip_vs_conn *cp) { struct ip_vs_conn_param p; |
19913dec1 ipvs: Pass ipvs n... |
138 |
ip_vs_conn_fill_param(cp->ipvs, cp->af, cp->protocol, |
6e67e586e IPVS: netns, conn... |
139 |
&cp->caddr, cp->cport, NULL, 0, &p); |
85999283a IPVS: Add struct ... |
140 |
|
e9e5eee87 IPVS: Add persist... |
141 142 |
if (cp->pe) { p.pe = cp->pe; |
85999283a IPVS: Add struct ... |
143 144 145 146 147 148 |
p.pe_data = cp->pe_data; p.pe_data_len = cp->pe_data_len; } return ip_vs_conn_hashkey_param(&p, false); } |
1da177e4c Linux-2.6.12-rc2 |
149 150 |
/* |
6e67e586e IPVS: netns, conn... |
151 |
* Hashes ip_vs_conn in ip_vs_conn_tab by netns,proto,addr,port. |
1da177e4c Linux-2.6.12-rc2 |
152 153 154 155 |
* returns bool success. */ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp) { |
95c961747 net: cleanup unsi... |
156 |
unsigned int hash; |
1da177e4c Linux-2.6.12-rc2 |
157 |
int ret; |
26ec037f9 IPVS: one-packet ... |
158 159 |
if (cp->flags & IP_VS_CONN_F_ONE_PACKET) return 0; |
1da177e4c Linux-2.6.12-rc2 |
160 |
/* Hash by protocol, client address and port */ |
85999283a IPVS: Add struct ... |
161 |
hash = ip_vs_conn_hashkey_conn(cp); |
1da177e4c Linux-2.6.12-rc2 |
162 |
|
ac69269a4 ipvs: do not disa... |
163 |
ct_write_lock_bh(hash); |
aea9d711f ipvs: Add missing... |
164 |
spin_lock(&cp->lock); |
1da177e4c Linux-2.6.12-rc2 |
165 166 |
if (!(cp->flags & IP_VS_CONN_F_HASHED)) { |
1da177e4c Linux-2.6.12-rc2 |
167 168 |
cp->flags |= IP_VS_CONN_F_HASHED; atomic_inc(&cp->refcnt); |
088339a57 ipvs: convert con... |
169 |
hlist_add_head_rcu(&cp->c_list, &ip_vs_conn_tab[hash]); |
1da177e4c Linux-2.6.12-rc2 |
170 171 |
ret = 1; } else { |
1e3e238e9 IPVS: use pr_err ... |
172 173 174 |
pr_err("%s(): request for already hashed, called from %pF ", __func__, __builtin_return_address(0)); |
1da177e4c Linux-2.6.12-rc2 |
175 176 |
ret = 0; } |
aea9d711f ipvs: Add missing... |
177 |
spin_unlock(&cp->lock); |
ac69269a4 ipvs: do not disa... |
178 |
ct_write_unlock_bh(hash); |
1da177e4c Linux-2.6.12-rc2 |
179 180 181 182 183 184 185 |
return ret; } /* * UNhashes ip_vs_conn from ip_vs_conn_tab. |
088339a57 ipvs: convert con... |
186 |
* returns bool success. Caller should hold conn reference. |
1da177e4c Linux-2.6.12-rc2 |
187 188 189 |
*/ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp) { |
95c961747 net: cleanup unsi... |
190 |
unsigned int hash; |
1da177e4c Linux-2.6.12-rc2 |
191 192 193 |
int ret; /* unhash it and decrease its reference counter */ |
85999283a IPVS: Add struct ... |
194 |
hash = ip_vs_conn_hashkey_conn(cp); |
1da177e4c Linux-2.6.12-rc2 |
195 |
|
ac69269a4 ipvs: do not disa... |
196 |
ct_write_lock_bh(hash); |
aea9d711f ipvs: Add missing... |
197 |
spin_lock(&cp->lock); |
1da177e4c Linux-2.6.12-rc2 |
198 199 |
if (cp->flags & IP_VS_CONN_F_HASHED) { |
088339a57 ipvs: convert con... |
200 |
hlist_del_rcu(&cp->c_list); |
1da177e4c Linux-2.6.12-rc2 |
201 202 203 204 205 |
cp->flags &= ~IP_VS_CONN_F_HASHED; atomic_dec(&cp->refcnt); ret = 1; } else ret = 0; |
aea9d711f ipvs: Add missing... |
206 |
spin_unlock(&cp->lock); |
ac69269a4 ipvs: do not disa... |
207 |
ct_write_unlock_bh(hash); |
1da177e4c Linux-2.6.12-rc2 |
208 209 210 |
return ret; } |
088339a57 ipvs: convert con... |
211 212 213 214 215 216 217 218 219 |
/* Try to unlink ip_vs_conn from ip_vs_conn_tab. * returns bool success. */ static inline bool ip_vs_conn_unlink(struct ip_vs_conn *cp) { unsigned int hash; bool ret; hash = ip_vs_conn_hashkey_conn(cp); |
ac69269a4 ipvs: do not disa... |
220 |
ct_write_lock_bh(hash); |
088339a57 ipvs: convert con... |
221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
spin_lock(&cp->lock); if (cp->flags & IP_VS_CONN_F_HASHED) { ret = false; /* Decrease refcnt and unlink conn only if we are last user */ if (atomic_cmpxchg(&cp->refcnt, 1, 0) == 1) { hlist_del_rcu(&cp->c_list); cp->flags &= ~IP_VS_CONN_F_HASHED; ret = true; } } else ret = atomic_read(&cp->refcnt) ? false : true; spin_unlock(&cp->lock); |
ac69269a4 ipvs: do not disa... |
235 |
ct_write_unlock_bh(hash); |
088339a57 ipvs: convert con... |
236 237 238 |
return ret; } |
1da177e4c Linux-2.6.12-rc2 |
239 240 241 242 |
/* * Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab. * Called for pkts coming from OUTside-to-INside. |
f11017ec2 IPVS: Add struct ... |
243 244 |
* p->caddr, p->cport: pkt source address (foreign host) * p->vaddr, p->vport: pkt dest address (load balancer) |
1da177e4c Linux-2.6.12-rc2 |
245 |
*/ |
f11017ec2 IPVS: Add struct ... |
246 247 |
static inline struct ip_vs_conn * __ip_vs_conn_in_get(const struct ip_vs_conn_param *p) |
1da177e4c Linux-2.6.12-rc2 |
248 |
{ |
95c961747 net: cleanup unsi... |
249 |
unsigned int hash; |
1da177e4c Linux-2.6.12-rc2 |
250 |
struct ip_vs_conn *cp; |
85999283a IPVS: Add struct ... |
251 |
hash = ip_vs_conn_hashkey_param(p, false); |
1da177e4c Linux-2.6.12-rc2 |
252 |
|
088339a57 ipvs: convert con... |
253 |
rcu_read_lock(); |
1da177e4c Linux-2.6.12-rc2 |
254 |
|
088339a57 ipvs: convert con... |
255 |
hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[hash], c_list) { |
1845ed0bb ipvs: reorder key... |
256 257 |
if (p->cport == cp->cport && p->vport == cp->vport && cp->af == p->af && |
f11017ec2 IPVS: Add struct ... |
258 259 |
ip_vs_addr_equal(p->af, p->caddr, &cp->caddr) && ip_vs_addr_equal(p->af, p->vaddr, &cp->vaddr) && |
f11017ec2 IPVS: Add struct ... |
260 |
((!p->cport) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) && |
6e67e586e IPVS: netns, conn... |
261 |
p->protocol == cp->protocol && |
e64e2b460 ipvs: Store ipvs ... |
262 |
cp->ipvs == p->ipvs) { |
088339a57 ipvs: convert con... |
263 264 |
if (!__ip_vs_conn_get(cp)) continue; |
1da177e4c Linux-2.6.12-rc2 |
265 |
/* HIT */ |
088339a57 ipvs: convert con... |
266 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
267 268 269 |
return cp; } } |
088339a57 ipvs: convert con... |
270 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
271 272 273 |
return NULL; } |
f11017ec2 IPVS: Add struct ... |
274 |
struct ip_vs_conn *ip_vs_conn_in_get(const struct ip_vs_conn_param *p) |
1da177e4c Linux-2.6.12-rc2 |
275 276 |
{ struct ip_vs_conn *cp; |
f11017ec2 IPVS: Add struct ... |
277 278 279 280 281 282 |
cp = __ip_vs_conn_in_get(p); if (!cp && atomic_read(&ip_vs_conn_no_cport_cnt)) { struct ip_vs_conn_param cport_zero_p = *p; cport_zero_p.cport = 0; cp = __ip_vs_conn_in_get(&cport_zero_p); } |
1da177e4c Linux-2.6.12-rc2 |
283 |
|
28364a59f IPVS: Extend func... |
284 285 |
IP_VS_DBG_BUF(9, "lookup/in %s %s:%d->%s:%d %s ", |
f11017ec2 IPVS: Add struct ... |
286 287 288 |
ip_vs_proto_name(p->protocol), IP_VS_DBG_ADDR(p->af, p->caddr), ntohs(p->cport), IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport), |
28364a59f IPVS: Extend func... |
289 |
cp ? "hit" : "not hit"); |
1da177e4c Linux-2.6.12-rc2 |
290 291 292 |
return cp; } |
f11017ec2 IPVS: Add struct ... |
293 |
static int |
f5099dd4d ipvs: Pass ipvs i... |
294 295 |
ip_vs_conn_fill_param_proto(struct netns_ipvs *ipvs, int af, const struct sk_buff *skb, |
f11017ec2 IPVS: Add struct ... |
296 |
const struct ip_vs_iphdr *iph, |
802c41adc ipvs: drop invers... |
297 |
struct ip_vs_conn_param *p) |
f11017ec2 IPVS: Add struct ... |
298 299 |
{ __be16 _ports[2], *pptr; |
d4383f04d ipvs: API change ... |
300 |
pptr = frag_safe_skb_hp(skb, iph->len, sizeof(_ports), _ports, iph); |
f11017ec2 IPVS: Add struct ... |
301 302 |
if (pptr == NULL) return 1; |
802c41adc ipvs: drop invers... |
303 |
if (likely(!ip_vs_iph_inverse(iph))) |
19913dec1 ipvs: Pass ipvs n... |
304 |
ip_vs_conn_fill_param(ipvs, af, iph->protocol, &iph->saddr, |
6e67e586e IPVS: netns, conn... |
305 |
pptr[0], &iph->daddr, pptr[1], p); |
f11017ec2 IPVS: Add struct ... |
306 |
else |
19913dec1 ipvs: Pass ipvs n... |
307 |
ip_vs_conn_fill_param(ipvs, af, iph->protocol, &iph->daddr, |
6e67e586e IPVS: netns, conn... |
308 |
pptr[1], &iph->saddr, pptr[0], p); |
f11017ec2 IPVS: Add struct ... |
309 310 |
return 0; } |
5c0d2374a ipvs: provide def... |
311 |
struct ip_vs_conn * |
ab1619764 ipvs: Pass ipvs i... |
312 313 |
ip_vs_conn_in_get_proto(struct netns_ipvs *ipvs, int af, const struct sk_buff *skb, |
802c41adc ipvs: drop invers... |
314 |
const struct ip_vs_iphdr *iph) |
5c0d2374a ipvs: provide def... |
315 |
{ |
f11017ec2 IPVS: Add struct ... |
316 |
struct ip_vs_conn_param p; |
5c0d2374a ipvs: provide def... |
317 |
|
f5099dd4d ipvs: Pass ipvs i... |
318 |
if (ip_vs_conn_fill_param_proto(ipvs, af, skb, iph, &p)) |
5c0d2374a ipvs: provide def... |
319 |
return NULL; |
f11017ec2 IPVS: Add struct ... |
320 |
return ip_vs_conn_in_get(&p); |
5c0d2374a ipvs: provide def... |
321 322 |
} EXPORT_SYMBOL_GPL(ip_vs_conn_in_get_proto); |
87375ab47 [IPVS]: ip_vs_ftp... |
323 |
/* Get reference to connection template */ |
f11017ec2 IPVS: Add struct ... |
324 |
struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p) |
87375ab47 [IPVS]: ip_vs_ftp... |
325 |
{ |
95c961747 net: cleanup unsi... |
326 |
unsigned int hash; |
87375ab47 [IPVS]: ip_vs_ftp... |
327 |
struct ip_vs_conn *cp; |
85999283a IPVS: Add struct ... |
328 |
hash = ip_vs_conn_hashkey_param(p, false); |
87375ab47 [IPVS]: ip_vs_ftp... |
329 |
|
088339a57 ipvs: convert con... |
330 |
rcu_read_lock(); |
87375ab47 [IPVS]: ip_vs_ftp... |
331 |
|
088339a57 ipvs: convert con... |
332 |
hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[hash], c_list) { |
1845ed0bb ipvs: reorder key... |
333 |
if (unlikely(p->pe_data && p->pe->ct_match)) { |
e64e2b460 ipvs: Store ipvs ... |
334 |
if (cp->ipvs != p->ipvs) |
1845ed0bb ipvs: reorder key... |
335 |
continue; |
088339a57 ipvs: convert con... |
336 337 338 339 |
if (p->pe == cp->pe && p->pe->ct_match(p, cp)) { if (__ip_vs_conn_get(cp)) goto out; } |
85999283a IPVS: Add struct ... |
340 341 |
continue; } |
f11017ec2 IPVS: Add struct ... |
342 343 |
if (cp->af == p->af && ip_vs_addr_equal(p->af, p->caddr, &cp->caddr) && |
be8be9ecc ipvs: Fix IPv4 FW... |
344 |
/* protocol should only be IPPROTO_IP if |
f11017ec2 IPVS: Add struct ... |
345 346 347 |
* p->vaddr is a fwmark */ ip_vs_addr_equal(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af, p->vaddr, &cp->vaddr) && |
1845ed0bb ipvs: reorder key... |
348 |
p->vport == cp->vport && p->cport == cp->cport && |
87375ab47 [IPVS]: ip_vs_ftp... |
349 |
cp->flags & IP_VS_CONN_F_TEMPLATE && |
1845ed0bb ipvs: reorder key... |
350 |
p->protocol == cp->protocol && |
e64e2b460 ipvs: Store ipvs ... |
351 |
cp->ipvs == p->ipvs) { |
088339a57 ipvs: convert con... |
352 353 354 |
if (__ip_vs_conn_get(cp)) goto out; } |
87375ab47 [IPVS]: ip_vs_ftp... |
355 356 357 358 |
} cp = NULL; out: |
088339a57 ipvs: convert con... |
359 |
rcu_read_unlock(); |
87375ab47 [IPVS]: ip_vs_ftp... |
360 |
|
28364a59f IPVS: Extend func... |
361 362 |
IP_VS_DBG_BUF(9, "template lookup/in %s %s:%d->%s:%d %s ", |
f11017ec2 IPVS: Add struct ... |
363 364 365 |
ip_vs_proto_name(p->protocol), IP_VS_DBG_ADDR(p->af, p->caddr), ntohs(p->cport), IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport), |
28364a59f IPVS: Extend func... |
366 |
cp ? "hit" : "not hit"); |
87375ab47 [IPVS]: ip_vs_ftp... |
367 368 369 |
return cp; } |
1da177e4c Linux-2.6.12-rc2 |
370 |
|
f11017ec2 IPVS: Add struct ... |
371 372 373 374 375 |
/* Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab. * Called for pkts coming from inside-to-OUTside. * p->caddr, p->cport: pkt source address (inside host) * p->vaddr, p->vport: pkt dest address (foreign host) */ struct ip_vs_conn *ip_vs_conn_out_get(const struct ip_vs_conn_param *p) |
1da177e4c Linux-2.6.12-rc2 |
376 |
{ |
95c961747 net: cleanup unsi... |
377 |
unsigned int hash; |
1da177e4c Linux-2.6.12-rc2 |
378 379 380 381 382 |
struct ip_vs_conn *cp, *ret=NULL; /* * Check for "full" addressed entries */ |
85999283a IPVS: Add struct ... |
383 |
hash = ip_vs_conn_hashkey_param(p, true); |
1da177e4c Linux-2.6.12-rc2 |
384 |
|
088339a57 ipvs: convert con... |
385 |
rcu_read_lock(); |
1da177e4c Linux-2.6.12-rc2 |
386 |
|
088339a57 ipvs: convert con... |
387 |
hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[hash], c_list) { |
1845ed0bb ipvs: reorder key... |
388 389 |
if (p->vport == cp->cport && p->cport == cp->dport && cp->af == p->af && |
f11017ec2 IPVS: Add struct ... |
390 391 |
ip_vs_addr_equal(p->af, p->vaddr, &cp->caddr) && ip_vs_addr_equal(p->af, p->caddr, &cp->daddr) && |
6e67e586e IPVS: netns, conn... |
392 |
p->protocol == cp->protocol && |
e64e2b460 ipvs: Store ipvs ... |
393 |
cp->ipvs == p->ipvs) { |
088339a57 ipvs: convert con... |
394 395 |
if (!__ip_vs_conn_get(cp)) continue; |
1da177e4c Linux-2.6.12-rc2 |
396 |
/* HIT */ |
1da177e4c Linux-2.6.12-rc2 |
397 398 399 400 |
ret = cp; break; } } |
088339a57 ipvs: convert con... |
401 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
402 |
|
28364a59f IPVS: Extend func... |
403 404 |
IP_VS_DBG_BUF(9, "lookup/out %s %s:%d->%s:%d %s ", |
f11017ec2 IPVS: Add struct ... |
405 406 407 |
ip_vs_proto_name(p->protocol), IP_VS_DBG_ADDR(p->af, p->caddr), ntohs(p->cport), IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport), |
28364a59f IPVS: Extend func... |
408 |
ret ? "hit" : "not hit"); |
1da177e4c Linux-2.6.12-rc2 |
409 410 411 |
return ret; } |
5c0d2374a ipvs: provide def... |
412 |
struct ip_vs_conn * |
0cf705c8c ipvs: Pass ipvs i... |
413 414 |
ip_vs_conn_out_get_proto(struct netns_ipvs *ipvs, int af, const struct sk_buff *skb, |
802c41adc ipvs: drop invers... |
415 |
const struct ip_vs_iphdr *iph) |
5c0d2374a ipvs: provide def... |
416 |
{ |
f11017ec2 IPVS: Add struct ... |
417 |
struct ip_vs_conn_param p; |
5c0d2374a ipvs: provide def... |
418 |
|
f5099dd4d ipvs: Pass ipvs i... |
419 |
if (ip_vs_conn_fill_param_proto(ipvs, af, skb, iph, &p)) |
5c0d2374a ipvs: provide def... |
420 |
return NULL; |
f11017ec2 IPVS: Add struct ... |
421 |
return ip_vs_conn_out_get(&p); |
5c0d2374a ipvs: provide def... |
422 423 |
} EXPORT_SYMBOL_GPL(ip_vs_conn_out_get_proto); |
1da177e4c Linux-2.6.12-rc2 |
424 |
|
013b04246 ipvs: optimize re... |
425 426 427 428 429 |
static void __ip_vs_conn_put_notimer(struct ip_vs_conn *cp) { __ip_vs_conn_put(cp); ip_vs_conn_expire((unsigned long)cp); } |
1da177e4c Linux-2.6.12-rc2 |
430 431 432 |
/* * Put back the conn and restart its timer with its timeout */ |
013b04246 ipvs: optimize re... |
433 |
static void __ip_vs_conn_put_timer(struct ip_vs_conn *cp) |
1da177e4c Linux-2.6.12-rc2 |
434 |
{ |
26ec037f9 IPVS: one-packet ... |
435 436 437 |
unsigned long t = (cp->flags & IP_VS_CONN_F_ONE_PACKET) ? 0 : cp->timeout; mod_timer(&cp->timer, jiffies+t); |
1da177e4c Linux-2.6.12-rc2 |
438 439 440 |
__ip_vs_conn_put(cp); } |
013b04246 ipvs: optimize re... |
441 442 443 444 445 446 447 448 449 450 |
void ip_vs_conn_put(struct ip_vs_conn *cp) { if ((cp->flags & IP_VS_CONN_F_ONE_PACKET) && (atomic_read(&cp->refcnt) == 1) && !timer_pending(&cp->timer)) /* expire connection immediately */ __ip_vs_conn_put_notimer(cp); else __ip_vs_conn_put_timer(cp); } |
1da177e4c Linux-2.6.12-rc2 |
451 452 453 454 |
/* * Fill a no_client_port connection with a client port number */ |
014d730d5 [IPVS]: ipvs anno... |
455 |
void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport) |
1da177e4c Linux-2.6.12-rc2 |
456 457 |
{ if (ip_vs_conn_unhash(cp)) { |
ac69269a4 ipvs: do not disa... |
458 |
spin_lock_bh(&cp->lock); |
1da177e4c Linux-2.6.12-rc2 |
459 460 461 462 463 |
if (cp->flags & IP_VS_CONN_F_NO_CPORT) { atomic_dec(&ip_vs_conn_no_cport_cnt); cp->flags &= ~IP_VS_CONN_F_NO_CPORT; cp->cport = cport; } |
ac69269a4 ipvs: do not disa... |
464 |
spin_unlock_bh(&cp->lock); |
1da177e4c Linux-2.6.12-rc2 |
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 |
/* hash on new dport */ ip_vs_conn_hash(cp); } } /* * Bind a connection entry with the corresponding packet_xmit. * Called by ip_vs_conn_new. */ static inline void ip_vs_bind_xmit(struct ip_vs_conn *cp) { switch (IP_VS_FWD_METHOD(cp)) { case IP_VS_CONN_F_MASQ: cp->packet_xmit = ip_vs_nat_xmit; break; case IP_VS_CONN_F_TUNNEL: |
8052ba292 ipvs: support ipv... |
484 485 486 487 488 489 |
#ifdef CONFIG_IP_VS_IPV6 if (cp->daf == AF_INET6) cp->packet_xmit = ip_vs_tunnel_xmit_v6; else #endif cp->packet_xmit = ip_vs_tunnel_xmit; |
1da177e4c Linux-2.6.12-rc2 |
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 |
break; case IP_VS_CONN_F_DROUTE: cp->packet_xmit = ip_vs_dr_xmit; break; case IP_VS_CONN_F_LOCALNODE: cp->packet_xmit = ip_vs_null_xmit; break; case IP_VS_CONN_F_BYPASS: cp->packet_xmit = ip_vs_bypass_xmit; break; } } |
b3cdd2a73 IPVS: Add and bin... |
505 506 507 508 509 510 511 512 513 |
#ifdef CONFIG_IP_VS_IPV6 static inline void ip_vs_bind_xmit_v6(struct ip_vs_conn *cp) { switch (IP_VS_FWD_METHOD(cp)) { case IP_VS_CONN_F_MASQ: cp->packet_xmit = ip_vs_nat_xmit_v6; break; case IP_VS_CONN_F_TUNNEL: |
8052ba292 ipvs: support ipv... |
514 515 516 517 |
if (cp->daf == AF_INET6) cp->packet_xmit = ip_vs_tunnel_xmit_v6; else cp->packet_xmit = ip_vs_tunnel_xmit; |
b3cdd2a73 IPVS: Add and bin... |
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 |
break; case IP_VS_CONN_F_DROUTE: cp->packet_xmit = ip_vs_dr_xmit_v6; break; case IP_VS_CONN_F_LOCALNODE: cp->packet_xmit = ip_vs_null_xmit; break; case IP_VS_CONN_F_BYPASS: cp->packet_xmit = ip_vs_bypass_xmit_v6; break; } } #endif |
1da177e4c Linux-2.6.12-rc2 |
534 535 536 537 538 539 540 541 542 543 544 545 546 547 |
static inline int ip_vs_dest_totalconns(struct ip_vs_dest *dest) { return atomic_read(&dest->activeconns) + atomic_read(&dest->inactconns); } /* * Bind a connection entry with a virtual service destination * Called just after a new connection entry is created. */ static inline void ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest) { |
3575792e0 ipvs: extend conn... |
548 |
unsigned int conn_flags; |
6b324dbfc ipvs: optimize th... |
549 |
__u32 flags; |
3575792e0 ipvs: extend conn... |
550 |
|
1da177e4c Linux-2.6.12-rc2 |
551 552 553 554 555 |
/* if dest is NULL, then return directly */ if (!dest) return; /* Increase the refcnt counter of the dest */ |
fca9c20ae ipvs: add ip_vs_d... |
556 |
ip_vs_dest_hold(dest); |
1da177e4c Linux-2.6.12-rc2 |
557 |
|
3575792e0 ipvs: extend conn... |
558 559 560 |
conn_flags = atomic_read(&dest->conn_flags); if (cp->protocol != IPPROTO_UDP) conn_flags &= ~IP_VS_CONN_F_ONE_PACKET; |
6b324dbfc ipvs: optimize th... |
561 |
flags = cp->flags; |
1da177e4c Linux-2.6.12-rc2 |
562 |
/* Bind with the destination and its corresponding transmitter */ |
6b324dbfc ipvs: optimize th... |
563 |
if (flags & IP_VS_CONN_F_SYNC) { |
b209639e8 [IPVS]: Create sy... |
564 565 566 |
/* if the connection is not template and is created * by sync, preserve the activity flag. */ |
6b324dbfc ipvs: optimize th... |
567 |
if (!(flags & IP_VS_CONN_F_TEMPLATE)) |
3575792e0 ipvs: extend conn... |
568 |
conn_flags &= ~IP_VS_CONN_F_INACTIVE; |
3233759be ipvs: inherit for... |
569 |
/* connections inherit forwarding method from dest */ |
6b324dbfc ipvs: optimize th... |
570 |
flags &= ~(IP_VS_CONN_F_FWD_MASK | IP_VS_CONN_F_NOOUTPUT); |
3575792e0 ipvs: extend conn... |
571 |
} |
6b324dbfc ipvs: optimize th... |
572 573 |
flags |= conn_flags; cp->flags = flags; |
1da177e4c Linux-2.6.12-rc2 |
574 |
cp->dest = dest; |
cfc78c5a0 IPVS: Adjust vari... |
575 576 577 578 579 580 581 |
IP_VS_DBG_BUF(7, "Bind-dest %s c:%s:%d v:%s:%d " "d:%s:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d " "dest->refcnt:%d ", ip_vs_proto_name(cp->protocol), IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport), IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport), |
f18ae7206 ipvs: use the new... |
582 |
IP_VS_DBG_ADDR(cp->daf, &cp->daddr), ntohs(cp->dport), |
cfc78c5a0 IPVS: Adjust vari... |
583 584 585 |
ip_vs_fwd_tag(cp), cp->state, cp->flags, atomic_read(&cp->refcnt), atomic_read(&dest->refcnt)); |
1da177e4c Linux-2.6.12-rc2 |
586 587 |
/* Update the connection counters */ |
6b324dbfc ipvs: optimize th... |
588 |
if (!(flags & IP_VS_CONN_F_TEMPLATE)) { |
06611f82c ipvs: remove chec... |
589 590 591 592 |
/* It is a normal connection, so modify the counters * according to the flags, later the protocol can * update them on state change */ |
6b324dbfc ipvs: optimize th... |
593 |
if (!(flags & IP_VS_CONN_F_INACTIVE)) |
b209639e8 [IPVS]: Create sy... |
594 595 596 |
atomic_inc(&dest->activeconns); else atomic_inc(&dest->inactconns); |
1da177e4c Linux-2.6.12-rc2 |
597 598 |
} else { /* It is a persistent connection/template, so increase |
25985edce Fix common misspe... |
599 |
the persistent connection counter */ |
1da177e4c Linux-2.6.12-rc2 |
600 601 602 603 604 605 606 607 608 609 |
atomic_inc(&dest->persistconns); } if (dest->u_threshold != 0 && ip_vs_dest_totalconns(dest) >= dest->u_threshold) dest->flags |= IP_VS_DEST_F_OVERLOAD; } /* |
1e356f9cd [IPVS]: Bind conn... |
610 611 612 |
* Check if there is a destination for the connection, if so * bind the connection to the destination. */ |
413c2d04e ipvs: convert des... |
613 |
void ip_vs_try_bind_dest(struct ip_vs_conn *cp) |
1e356f9cd [IPVS]: Bind conn... |
614 615 |
{ struct ip_vs_dest *dest; |
413c2d04e ipvs: convert des... |
616 |
rcu_read_lock(); |
655eef103 ipvs: Supply dest... |
617 618 619 620 621 622 |
/* This function is only invoked by the synchronization code. We do * not currently support heterogeneous pools with synchronization, * so we can make the assumption that the svc_af is the same as the * dest_af */ |
dc2add6f2 ipvs: Pass ipvs n... |
623 |
dest = ip_vs_find_dest(cp->ipvs, cp->af, cp->af, &cp->daddr, |
882a844bd ipvs: fix ip_vs_t... |
624 625 626 627 |
cp->dport, &cp->vaddr, cp->vport, cp->protocol, cp->fwmark, cp->flags); if (dest) { struct ip_vs_proto_data *pd; |
ac69269a4 ipvs: do not disa... |
628 |
spin_lock_bh(&cp->lock); |
f73181c82 ipvs: add support... |
629 |
if (cp->dest) { |
ac69269a4 ipvs: do not disa... |
630 |
spin_unlock_bh(&cp->lock); |
413c2d04e ipvs: convert des... |
631 632 |
rcu_read_unlock(); return; |
f73181c82 ipvs: add support... |
633 |
} |
882a844bd ipvs: fix ip_vs_t... |
634 635 636 637 |
/* Applications work depending on the forwarding method * but better to reassign them always when binding dest */ if (cp->app) ip_vs_unbind_app(cp); |
1e356f9cd [IPVS]: Bind conn... |
638 |
ip_vs_bind_dest(cp, dest); |
ac69269a4 ipvs: do not disa... |
639 |
spin_unlock_bh(&cp->lock); |
882a844bd ipvs: fix ip_vs_t... |
640 641 642 643 644 645 646 647 648 |
/* Update its packet transmitter */ cp->packet_xmit = NULL; #ifdef CONFIG_IP_VS_IPV6 if (cp->af == AF_INET6) ip_vs_bind_xmit_v6(cp); else #endif ip_vs_bind_xmit(cp); |
18d6ade63 ipvs: Pass ipvs n... |
649 |
pd = ip_vs_proto_data_get(cp->ipvs, cp->protocol); |
882a844bd ipvs: fix ip_vs_t... |
650 651 652 |
if (pd && atomic_read(&pd->appcnt)) ip_vs_bind_app(cp, pd->pp); } |
413c2d04e ipvs: convert des... |
653 |
rcu_read_unlock(); |
1e356f9cd [IPVS]: Bind conn... |
654 |
} |
1e356f9cd [IPVS]: Bind conn... |
655 656 657 |
/* |
1da177e4c Linux-2.6.12-rc2 |
658 659 660 661 662 663 664 665 666 |
* Unbind a connection entry with its VS destination * Called by the ip_vs_conn_expire function. */ static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp) { struct ip_vs_dest *dest = cp->dest; if (!dest) return; |
cfc78c5a0 IPVS: Adjust vari... |
667 668 669 670 671 672 673 |
IP_VS_DBG_BUF(7, "Unbind-dest %s c:%s:%d v:%s:%d " "d:%s:%d fwd:%c s:%u conn->flags:%X conn->refcnt:%d " "dest->refcnt:%d ", ip_vs_proto_name(cp->protocol), IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport), IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport), |
f18ae7206 ipvs: use the new... |
674 |
IP_VS_DBG_ADDR(cp->daf, &cp->daddr), ntohs(cp->dport), |
cfc78c5a0 IPVS: Adjust vari... |
675 676 677 |
ip_vs_fwd_tag(cp), cp->state, cp->flags, atomic_read(&cp->refcnt), atomic_read(&dest->refcnt)); |
1da177e4c Linux-2.6.12-rc2 |
678 679 |
/* Update the connection counters */ |
87375ab47 [IPVS]: ip_vs_ftp... |
680 |
if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) { |
1da177e4c Linux-2.6.12-rc2 |
681 682 683 684 685 686 687 688 689 |
/* It is a normal connection, so decrease the inactconns or activeconns counter */ if (cp->flags & IP_VS_CONN_F_INACTIVE) { atomic_dec(&dest->inactconns); } else { atomic_dec(&dest->activeconns); } } else { /* It is a persistent connection/template, so decrease |
25985edce Fix common misspe... |
690 |
the persistent connection counter */ |
1da177e4c Linux-2.6.12-rc2 |
691 692 693 694 695 696 697 698 699 700 701 702 703 |
atomic_dec(&dest->persistconns); } if (dest->l_threshold != 0) { if (ip_vs_dest_totalconns(dest) < dest->l_threshold) dest->flags &= ~IP_VS_DEST_F_OVERLOAD; } else if (dest->u_threshold != 0) { if (ip_vs_dest_totalconns(dest) * 4 < dest->u_threshold * 3) dest->flags &= ~IP_VS_DEST_F_OVERLOAD; } else { if (dest->flags & IP_VS_DEST_F_OVERLOAD) dest->flags &= ~IP_VS_DEST_F_OVERLOAD; } |
fca9c20ae ipvs: add ip_vs_d... |
704 |
ip_vs_dest_put(dest); |
1da177e4c Linux-2.6.12-rc2 |
705 |
} |
8e1b0b1b5 IPVS: Add expire_... |
706 707 708 709 710 711 712 713 714 715 |
static int expire_quiescent_template(struct netns_ipvs *ipvs, struct ip_vs_dest *dest) { #ifdef CONFIG_SYSCTL return ipvs->sysctl_expire_quiescent_template && (atomic_read(&dest->weight) == 0); #else return 0; #endif } |
1da177e4c Linux-2.6.12-rc2 |
716 717 718 719 720 721 |
/* * Checking if the destination of a connection template is available. * If available, return 1, otherwise invalidate this connection * template and return 0. */ |
3ec10d3a2 ipvs: update real... |
722 |
int ip_vs_check_template(struct ip_vs_conn *ct, struct ip_vs_dest *cdest) |
1da177e4c Linux-2.6.12-rc2 |
723 724 |
{ struct ip_vs_dest *dest = ct->dest; |
58dbc6f26 ipvs: Store ipvs ... |
725 |
struct netns_ipvs *ipvs = ct->ipvs; |
1da177e4c Linux-2.6.12-rc2 |
726 727 728 729 730 |
/* * Checking the dest server status. */ if ((dest == NULL) || |
e905a9eda [NET] IPV4: Fix w... |
731 |
!(dest->flags & IP_VS_DEST_F_AVAILABLE) || |
3ec10d3a2 ipvs: update real... |
732 733 |
expire_quiescent_template(ipvs, dest) || (cdest && (dest != cdest))) { |
cfc78c5a0 IPVS: Adjust vari... |
734 735 736 737 738 739 740 741 742 |
IP_VS_DBG_BUF(9, "check_template: dest not available for " "protocol %s s:%s:%d v:%s:%d " "-> d:%s:%d ", ip_vs_proto_name(ct->protocol), IP_VS_DBG_ADDR(ct->af, &ct->caddr), ntohs(ct->cport), IP_VS_DBG_ADDR(ct->af, &ct->vaddr), ntohs(ct->vport), |
f18ae7206 ipvs: use the new... |
743 |
IP_VS_DBG_ADDR(ct->daf, &ct->daddr), |
cfc78c5a0 IPVS: Adjust vari... |
744 |
ntohs(ct->dport)); |
1da177e4c Linux-2.6.12-rc2 |
745 746 747 748 |
/* * Invalidate the connection template */ |
014d730d5 [IPVS]: ipvs anno... |
749 |
if (ct->vport != htons(0xffff)) { |
1da177e4c Linux-2.6.12-rc2 |
750 |
if (ip_vs_conn_unhash(ct)) { |
014d730d5 [IPVS]: ipvs anno... |
751 752 |
ct->dport = htons(0xffff); ct->vport = htons(0xffff); |
1da177e4c Linux-2.6.12-rc2 |
753 754 755 756 757 758 759 760 761 |
ct->cport = 0; ip_vs_conn_hash(ct); } } /* * Simply decrease the refcnt of the template, * don't restart its timer. */ |
088339a57 ipvs: convert con... |
762 |
__ip_vs_conn_put(ct); |
1da177e4c Linux-2.6.12-rc2 |
763 764 765 766 |
return 0; } return 1; } |
088339a57 ipvs: convert con... |
767 768 769 770 771 772 773 774 775 |
static void ip_vs_conn_rcu_free(struct rcu_head *head) { struct ip_vs_conn *cp = container_of(head, struct ip_vs_conn, rcu_head); ip_vs_pe_put(cp->pe); kfree(cp->pe_data); kmem_cache_free(ip_vs_conn_cachep, cp); } |
1da177e4c Linux-2.6.12-rc2 |
776 777 778 |
static void ip_vs_conn_expire(unsigned long data) { struct ip_vs_conn *cp = (struct ip_vs_conn *)data; |
58dbc6f26 ipvs: Store ipvs ... |
779 |
struct netns_ipvs *ipvs = cp->ipvs; |
1da177e4c Linux-2.6.12-rc2 |
780 |
|
1da177e4c Linux-2.6.12-rc2 |
781 782 783 784 785 |
/* * do I control anybody? */ if (atomic_read(&cp->n_control)) goto expire_later; |
088339a57 ipvs: convert con... |
786 787 |
/* Unlink conn if not referenced anymore */ if (likely(ip_vs_conn_unlink(cp))) { |
1da177e4c Linux-2.6.12-rc2 |
788 |
/* delete the timer if it is activated by other users */ |
25cc4ae91 net: remove redun... |
789 |
del_timer(&cp->timer); |
1da177e4c Linux-2.6.12-rc2 |
790 791 792 793 |
/* does anybody control me? */ if (cp->control) ip_vs_control_del(cp); |
8fb04d9fc ipvs: don't alter... |
794 795 |
if ((cp->flags & IP_VS_CONN_F_NFCT) && !(cp->flags & IP_VS_CONN_F_ONE_PACKET)) { |
8f4e0a186 IPVS netns exit c... |
796 797 798 799 800 801 802 803 |
/* Do not access conntracks during subsys cleanup * because nf_conntrack_find_get can not be used after * conntrack cleanup for the net. */ smp_rmb(); if (ipvs->enable) ip_vs_conn_drop_conntrack(cp); } |
f4bc17cdd ipvs: netfilter c... |
804 |
|
1da177e4c Linux-2.6.12-rc2 |
805 806 807 808 809 |
if (unlikely(cp->app != NULL)) ip_vs_unbind_app(cp); ip_vs_unbind_dest(cp); if (cp->flags & IP_VS_CONN_F_NO_CPORT) atomic_dec(&ip_vs_conn_no_cport_cnt); |
013b04246 ipvs: optimize re... |
810 811 812 813 |
if (cp->flags & IP_VS_CONN_F_ONE_PACKET) ip_vs_conn_rcu_free(&cp->rcu_head); else call_rcu(&cp->rcu_head, ip_vs_conn_rcu_free); |
6e67e586e IPVS: netns, conn... |
814 |
atomic_dec(&ipvs->conn_count); |
1da177e4c Linux-2.6.12-rc2 |
815 816 |
return; } |
1da177e4c Linux-2.6.12-rc2 |
817 |
expire_later: |
088339a57 ipvs: convert con... |
818 819 820 |
IP_VS_DBG(7, "delayed: conn->refcnt=%d conn->n_control=%d ", atomic_read(&cp->refcnt), |
1da177e4c Linux-2.6.12-rc2 |
821 |
atomic_read(&cp->n_control)); |
088339a57 ipvs: convert con... |
822 823 |
atomic_inc(&cp->refcnt); cp->timeout = 60*HZ; |
749c42b62 ipvs: reduce sync... |
824 |
if (ipvs->sync_state & IP_VS_STATE_MASTER) |
b61a8c1a4 ipvs: Pass ipvs n... |
825 |
ip_vs_sync_conn(ipvs, cp, sysctl_sync_threshold(ipvs)); |
749c42b62 ipvs: reduce sync... |
826 |
|
013b04246 ipvs: optimize re... |
827 |
__ip_vs_conn_put_timer(cp); |
1da177e4c Linux-2.6.12-rc2 |
828 |
} |
088339a57 ipvs: convert con... |
829 830 831 |
/* Modify timer, so that it expires as soon as possible. * Can be called without reference only if under RCU lock. */ |
1da177e4c Linux-2.6.12-rc2 |
832 833 |
void ip_vs_conn_expire_now(struct ip_vs_conn *cp) { |
088339a57 ipvs: convert con... |
834 835 836 837 838 839 |
/* Using mod_timer_pending will ensure the timer is not * modified after the final del_timer in ip_vs_conn_expire. */ if (timer_pending(&cp->timer) && time_after(cp->timer.expires, jiffies)) mod_timer_pending(&cp->timer, jiffies); |
1da177e4c Linux-2.6.12-rc2 |
840 841 842 843 844 845 846 |
} /* * Create a new connection entry and hash it into the ip_vs_conn_tab */ struct ip_vs_conn * |
ba38528aa ipvs: Supply dest... |
847 |
ip_vs_conn_new(const struct ip_vs_conn_param *p, int dest_af, |
95c961747 net: cleanup unsi... |
848 |
const union nf_inet_addr *daddr, __be16 dport, unsigned int flags, |
0e051e683 IPVS: Backup, Pre... |
849 |
struct ip_vs_dest *dest, __u32 fwmark) |
1da177e4c Linux-2.6.12-rc2 |
850 851 |
{ struct ip_vs_conn *cp; |
e64e2b460 ipvs: Store ipvs ... |
852 |
struct netns_ipvs *ipvs = p->ipvs; |
18d6ade63 ipvs: Pass ipvs n... |
853 |
struct ip_vs_proto_data *pd = ip_vs_proto_data_get(p->ipvs, |
6e67e586e IPVS: netns, conn... |
854 |
p->protocol); |
1da177e4c Linux-2.6.12-rc2 |
855 |
|
9a05475ce ipvs: avoid kmem_... |
856 |
cp = kmem_cache_alloc(ip_vs_conn_cachep, GFP_ATOMIC); |
1da177e4c Linux-2.6.12-rc2 |
857 |
if (cp == NULL) { |
1e3e238e9 IPVS: use pr_err ... |
858 859 |
IP_VS_ERR_RL("%s(): no memory ", __func__); |
1da177e4c Linux-2.6.12-rc2 |
860 861 |
return NULL; } |
731109e78 ipvs: use hlist i... |
862 |
INIT_HLIST_NODE(&cp->c_list); |
b24b8a247 [NET]: Convert in... |
863 |
setup_timer(&cp->timer, ip_vs_conn_expire, (unsigned long)cp); |
58dbc6f26 ipvs: Store ipvs ... |
864 |
cp->ipvs = ipvs; |
f11017ec2 IPVS: Add struct ... |
865 |
cp->af = p->af; |
ba38528aa ipvs: Supply dest... |
866 |
cp->daf = dest_af; |
f11017ec2 IPVS: Add struct ... |
867 |
cp->protocol = p->protocol; |
9a05475ce ipvs: avoid kmem_... |
868 |
ip_vs_addr_set(p->af, &cp->caddr, p->caddr); |
f11017ec2 IPVS: Add struct ... |
869 |
cp->cport = p->cport; |
2a971354e ipvs: fix AF assi... |
870 |
/* proto should only be IPPROTO_IP if p->vaddr is a fwmark */ |
9a05475ce ipvs: avoid kmem_... |
871 |
ip_vs_addr_set(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af, |
2a971354e ipvs: fix AF assi... |
872 873 |
&cp->vaddr, p->vaddr); cp->vport = p->vport; |
ba38528aa ipvs: Supply dest... |
874 |
ip_vs_addr_set(cp->daf, &cp->daddr, daddr); |
1da177e4c Linux-2.6.12-rc2 |
875 876 |
cp->dport = dport; cp->flags = flags; |
0e051e683 IPVS: Backup, Pre... |
877 |
cp->fwmark = fwmark; |
e9e5eee87 IPVS: Add persist... |
878 879 880 |
if (flags & IP_VS_CONN_F_TEMPLATE && p->pe) { ip_vs_pe_get(p->pe); cp->pe = p->pe; |
85999283a IPVS: Add struct ... |
881 882 |
cp->pe_data = p->pe_data; cp->pe_data_len = p->pe_data_len; |
9a05475ce ipvs: avoid kmem_... |
883 884 885 886 |
} else { cp->pe = NULL; cp->pe_data = NULL; cp->pe_data_len = 0; |
85999283a IPVS: Add struct ... |
887 |
} |
1da177e4c Linux-2.6.12-rc2 |
888 889 890 891 892 893 894 895 |
spin_lock_init(&cp->lock); /* * Set the entry is referenced by the current thread before hashing * it in the table, so that other thread run ip_vs_random_dropentry * but cannot drop this entry. */ atomic_set(&cp->refcnt, 1); |
9a05475ce ipvs: avoid kmem_... |
896 |
cp->control = NULL; |
1da177e4c Linux-2.6.12-rc2 |
897 898 |
atomic_set(&cp->n_control, 0); atomic_set(&cp->in_pkts, 0); |
9a05475ce ipvs: avoid kmem_... |
899 900 901 902 903 904 |
cp->packet_xmit = NULL; cp->app = NULL; cp->app_data = NULL; /* reset struct ip_vs_seq */ cp->in_seq.delta = 0; cp->out_seq.delta = 0; |
6e67e586e IPVS: netns, conn... |
905 |
atomic_inc(&ipvs->conn_count); |
1da177e4c Linux-2.6.12-rc2 |
906 907 908 909 |
if (flags & IP_VS_CONN_F_NO_CPORT) atomic_inc(&ip_vs_conn_no_cport_cnt); /* Bind the connection with a destination server */ |
9a05475ce ipvs: avoid kmem_... |
910 |
cp->dest = NULL; |
1da177e4c Linux-2.6.12-rc2 |
911 912 913 914 |
ip_vs_bind_dest(cp, dest); /* Set its state and timeout */ cp->state = 0; |
9a05475ce ipvs: avoid kmem_... |
915 |
cp->old_state = 0; |
1da177e4c Linux-2.6.12-rc2 |
916 |
cp->timeout = 3*HZ; |
749c42b62 ipvs: reduce sync... |
917 |
cp->sync_endtime = jiffies & ~3UL; |
1da177e4c Linux-2.6.12-rc2 |
918 919 |
/* Bind its packet transmitter */ |
b3cdd2a73 IPVS: Add and bin... |
920 |
#ifdef CONFIG_IP_VS_IPV6 |
f11017ec2 IPVS: Add struct ... |
921 |
if (p->af == AF_INET6) |
b3cdd2a73 IPVS: Add and bin... |
922 923 924 925 |
ip_vs_bind_xmit_v6(cp); else #endif ip_vs_bind_xmit(cp); |
1da177e4c Linux-2.6.12-rc2 |
926 |
|
9bbac6a90 IPVS: netns, comm... |
927 928 |
if (unlikely(pd && atomic_read(&pd->appcnt))) ip_vs_bind_app(cp, pd->pp); |
1da177e4c Linux-2.6.12-rc2 |
929 |
|
f4bc17cdd ipvs: netfilter c... |
930 931 932 933 934 935 |
/* * Allow conntrack to be preserved. By default, conntrack * is created and destroyed for every packet. * Sometimes keeping conntrack can be useful for * IP_VS_CONN_F_ONE_PACKET too. */ |
a0840e2e1 IPVS: netns, ip_v... |
936 |
if (ip_vs_conntrack_enabled(ipvs)) |
f4bc17cdd ipvs: netfilter c... |
937 |
cp->flags |= IP_VS_CONN_F_NFCT; |
1da177e4c Linux-2.6.12-rc2 |
938 939 940 941 942 |
/* Hash it in the ip_vs_conn_tab finally */ ip_vs_conn_hash(cp); return cp; } |
1da177e4c Linux-2.6.12-rc2 |
943 944 945 946 |
/* * /proc/net/ip_vs_conn entries */ #ifdef CONFIG_PROC_FS |
6e67e586e IPVS: netns, conn... |
947 |
struct ip_vs_iter_state { |
731109e78 ipvs: use hlist i... |
948 949 |
struct seq_net_private p; struct hlist_head *l; |
6e67e586e IPVS: netns, conn... |
950 |
}; |
1da177e4c Linux-2.6.12-rc2 |
951 952 953 954 955 |
static void *ip_vs_conn_array(struct seq_file *seq, loff_t pos) { int idx; struct ip_vs_conn *cp; |
6e67e586e IPVS: netns, conn... |
956 |
struct ip_vs_iter_state *iter = seq->private; |
e905a9eda [NET] IPV4: Fix w... |
957 |
|
6f7edb488 IPVS: Allow boot ... |
958 |
for (idx = 0; idx < ip_vs_conn_tab_size; idx++) { |
088339a57 ipvs: convert con... |
959 960 961 962 |
hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[idx], c_list) { /* __ip_vs_conn_get() is not needed by * ip_vs_conn_seq_show and ip_vs_conn_sync_seq_show */ |
1da177e4c Linux-2.6.12-rc2 |
963 |
if (pos-- == 0) { |
6e67e586e IPVS: netns, conn... |
964 |
iter->l = &ip_vs_conn_tab[idx]; |
731109e78 ipvs: use hlist i... |
965 |
return cp; |
1da177e4c Linux-2.6.12-rc2 |
966 967 |
} } |
a38e5e230 ipvs: use cond_re... |
968 |
cond_resched_rcu(); |
1da177e4c Linux-2.6.12-rc2 |
969 970 971 972 973 974 |
} return NULL; } static void *ip_vs_conn_seq_start(struct seq_file *seq, loff_t *pos) |
7cf2eb7bc ipvs: fix sparse ... |
975 |
__acquires(RCU) |
1da177e4c Linux-2.6.12-rc2 |
976 |
{ |
6e67e586e IPVS: netns, conn... |
977 978 979 |
struct ip_vs_iter_state *iter = seq->private; iter->l = NULL; |
7cf2eb7bc ipvs: fix sparse ... |
980 |
rcu_read_lock(); |
1da177e4c Linux-2.6.12-rc2 |
981 982 983 984 985 986 |
return *pos ? ip_vs_conn_array(seq, *pos - 1) :SEQ_START_TOKEN; } static void *ip_vs_conn_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct ip_vs_conn *cp = v; |
6e67e586e IPVS: netns, conn... |
987 |
struct ip_vs_iter_state *iter = seq->private; |
088339a57 ipvs: convert con... |
988 |
struct hlist_node *e; |
731109e78 ipvs: use hlist i... |
989 |
struct hlist_head *l = iter->l; |
1da177e4c Linux-2.6.12-rc2 |
990 991 992 |
int idx; ++*pos; |
e905a9eda [NET] IPV4: Fix w... |
993 |
if (v == SEQ_START_TOKEN) |
1da177e4c Linux-2.6.12-rc2 |
994 995 996 |
return ip_vs_conn_array(seq, 0); /* more on same hash chain? */ |
088339a57 ipvs: convert con... |
997 998 999 |
e = rcu_dereference(hlist_next_rcu(&cp->c_list)); if (e) return hlist_entry(e, struct ip_vs_conn, c_list); |
1da177e4c Linux-2.6.12-rc2 |
1000 1001 |
idx = l - ip_vs_conn_tab; |
6f7edb488 IPVS: Allow boot ... |
1002 |
while (++idx < ip_vs_conn_tab_size) { |
088339a57 ipvs: convert con... |
1003 |
hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[idx], c_list) { |
6e67e586e IPVS: netns, conn... |
1004 |
iter->l = &ip_vs_conn_tab[idx]; |
1da177e4c Linux-2.6.12-rc2 |
1005 |
return cp; |
e905a9eda [NET] IPV4: Fix w... |
1006 |
} |
a38e5e230 ipvs: use cond_re... |
1007 |
cond_resched_rcu(); |
1da177e4c Linux-2.6.12-rc2 |
1008 |
} |
6e67e586e IPVS: netns, conn... |
1009 |
iter->l = NULL; |
1da177e4c Linux-2.6.12-rc2 |
1010 1011 1012 1013 |
return NULL; } static void ip_vs_conn_seq_stop(struct seq_file *seq, void *v) |
7cf2eb7bc ipvs: fix sparse ... |
1014 |
__releases(RCU) |
1da177e4c Linux-2.6.12-rc2 |
1015 |
{ |
7cf2eb7bc ipvs: fix sparse ... |
1016 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
1017 1018 1019 1020 1021 1022 1023 |
} static int ip_vs_conn_seq_show(struct seq_file *seq, void *v) { if (v == SEQ_START_TOKEN) seq_puts(seq, |
a3c918acd IPVS: Add persist... |
1024 1025 |
"Pro FromIP FPrt ToIP TPrt DestIP DPrt State Expires PEName PEData "); |
1da177e4c Linux-2.6.12-rc2 |
1026 1027 |
else { const struct ip_vs_conn *cp = v; |
6e67e586e IPVS: netns, conn... |
1028 |
struct net *net = seq_file_net(seq); |
a3c918acd IPVS: Add persist... |
1029 1030 |
char pe_data[IP_VS_PENAME_MAXLEN + IP_VS_PEDATA_MAXLEN + 3]; size_t len = 0; |
f18ae7206 ipvs: use the new... |
1031 |
char dbuf[IP_VS_ADDRSTRLEN]; |
a3c918acd IPVS: Add persist... |
1032 |
|
58dbc6f26 ipvs: Store ipvs ... |
1033 |
if (!net_eq(cp->ipvs->net, net)) |
6e67e586e IPVS: netns, conn... |
1034 |
return 0; |
e9e5eee87 IPVS: Add persist... |
1035 |
if (cp->pe_data) { |
a3c918acd IPVS: Add persist... |
1036 |
pe_data[0] = ' '; |
e9e5eee87 IPVS: Add persist... |
1037 1038 |
len = strlen(cp->pe->name); memcpy(pe_data + 1, cp->pe->name, len); |
a3c918acd IPVS: Add persist... |
1039 1040 |
pe_data[len + 1] = ' '; len += 2; |
e9e5eee87 IPVS: Add persist... |
1041 |
len += cp->pe->show_pe_data(cp, pe_data + len); |
a3c918acd IPVS: Add persist... |
1042 1043 |
} pe_data[len] = '\0'; |
1da177e4c Linux-2.6.12-rc2 |
1044 |
|
667a5f181 IPVS: Convert pro... |
1045 |
#ifdef CONFIG_IP_VS_IPV6 |
f18ae7206 ipvs: use the new... |
1046 1047 1048 1049 1050 1051 1052 1053 |
if (cp->daf == AF_INET6) snprintf(dbuf, sizeof(dbuf), "%pI6", &cp->daddr.in6); else #endif snprintf(dbuf, sizeof(dbuf), "%08X", ntohl(cp->daddr.ip)); #ifdef CONFIG_IP_VS_IPV6 |
667a5f181 IPVS: Convert pro... |
1054 |
if (cp->af == AF_INET6) |
a3c918acd IPVS: Add persist... |
1055 |
seq_printf(seq, "%-3s %pI6 %04X %pI6 %04X " |
f18ae7206 ipvs: use the new... |
1056 1057 |
"%s %04X %-11s %7lu%s ", |
667a5f181 IPVS: Convert pro... |
1058 |
ip_vs_proto_name(cp->protocol), |
38ff4fa49 netfilter: replac... |
1059 1060 |
&cp->caddr.in6, ntohs(cp->cport), &cp->vaddr.in6, ntohs(cp->vport), |
f18ae7206 ipvs: use the new... |
1061 |
dbuf, ntohs(cp->dport), |
667a5f181 IPVS: Convert pro... |
1062 |
ip_vs_state_name(cp->protocol, cp->state), |
a3c918acd IPVS: Add persist... |
1063 |
(cp->timer.expires-jiffies)/HZ, pe_data); |
667a5f181 IPVS: Convert pro... |
1064 1065 1066 1067 |
else #endif seq_printf(seq, "%-3s %08X %04X %08X %04X" |
f18ae7206 ipvs: use the new... |
1068 1069 |
" %s %04X %-11s %7lu%s ", |
1da177e4c Linux-2.6.12-rc2 |
1070 |
ip_vs_proto_name(cp->protocol), |
e7ade46a5 IPVS: Change IPVS... |
1071 1072 |
ntohl(cp->caddr.ip), ntohs(cp->cport), ntohl(cp->vaddr.ip), ntohs(cp->vport), |
f18ae7206 ipvs: use the new... |
1073 |
dbuf, ntohs(cp->dport), |
1da177e4c Linux-2.6.12-rc2 |
1074 |
ip_vs_state_name(cp->protocol, cp->state), |
a3c918acd IPVS: Add persist... |
1075 |
(cp->timer.expires-jiffies)/HZ, pe_data); |
1da177e4c Linux-2.6.12-rc2 |
1076 1077 1078 |
} return 0; } |
56b3d975b [NET]: Make all i... |
1079 |
static const struct seq_operations ip_vs_conn_seq_ops = { |
1da177e4c Linux-2.6.12-rc2 |
1080 1081 1082 1083 1084 1085 1086 1087 |
.start = ip_vs_conn_seq_start, .next = ip_vs_conn_seq_next, .stop = ip_vs_conn_seq_stop, .show = ip_vs_conn_seq_show, }; static int ip_vs_conn_open(struct inode *inode, struct file *file) { |
6e67e586e IPVS: netns, conn... |
1088 1089 |
return seq_open_net(inode, file, &ip_vs_conn_seq_ops, sizeof(struct ip_vs_iter_state)); |
1da177e4c Linux-2.6.12-rc2 |
1090 |
} |
9a32144e9 [PATCH] mark stru... |
1091 |
static const struct file_operations ip_vs_conn_fops = { |
1da177e4c Linux-2.6.12-rc2 |
1092 1093 1094 1095 |
.owner = THIS_MODULE, .open = ip_vs_conn_open, .read = seq_read, .llseek = seq_lseek, |
0f08190fe IPVS: fix netns i... |
1096 |
.release = seq_release_net, |
1da177e4c Linux-2.6.12-rc2 |
1097 |
}; |
7a4fbb1fa [IPVS]: Flag sync... |
1098 |
|
95c961747 net: cleanup unsi... |
1099 |
static const char *ip_vs_origin_name(unsigned int flags) |
7a4fbb1fa [IPVS]: Flag sync... |
1100 1101 1102 1103 1104 1105 1106 1107 1108 |
{ if (flags & IP_VS_CONN_F_SYNC) return "SYNC"; else return "LOCAL"; } static int ip_vs_conn_sync_seq_show(struct seq_file *seq, void *v) { |
f18ae7206 ipvs: use the new... |
1109 |
char dbuf[IP_VS_ADDRSTRLEN]; |
7a4fbb1fa [IPVS]: Flag sync... |
1110 1111 1112 1113 1114 1115 1116 |
if (v == SEQ_START_TOKEN) seq_puts(seq, "Pro FromIP FPrt ToIP TPrt DestIP DPrt State Origin Expires "); else { const struct ip_vs_conn *cp = v; |
6e67e586e IPVS: netns, conn... |
1117 |
struct net *net = seq_file_net(seq); |
58dbc6f26 ipvs: Store ipvs ... |
1118 |
if (!net_eq(cp->ipvs->net, net)) |
6e67e586e IPVS: netns, conn... |
1119 |
return 0; |
7a4fbb1fa [IPVS]: Flag sync... |
1120 |
|
667a5f181 IPVS: Convert pro... |
1121 |
#ifdef CONFIG_IP_VS_IPV6 |
f18ae7206 ipvs: use the new... |
1122 1123 1124 1125 1126 1127 1128 1129 |
if (cp->daf == AF_INET6) snprintf(dbuf, sizeof(dbuf), "%pI6", &cp->daddr.in6); else #endif snprintf(dbuf, sizeof(dbuf), "%08X", ntohl(cp->daddr.ip)); #ifdef CONFIG_IP_VS_IPV6 |
667a5f181 IPVS: Convert pro... |
1130 |
if (cp->af == AF_INET6) |
f18ae7206 ipvs: use the new... |
1131 1132 1133 |
seq_printf(seq, "%-3s %pI6 %04X %pI6 %04X " "%s %04X %-11s %-6s %7lu ", |
667a5f181 IPVS: Convert pro... |
1134 |
ip_vs_proto_name(cp->protocol), |
38ff4fa49 netfilter: replac... |
1135 1136 |
&cp->caddr.in6, ntohs(cp->cport), &cp->vaddr.in6, ntohs(cp->vport), |
f18ae7206 ipvs: use the new... |
1137 |
dbuf, ntohs(cp->dport), |
667a5f181 IPVS: Convert pro... |
1138 1139 1140 1141 1142 1143 1144 |
ip_vs_state_name(cp->protocol, cp->state), ip_vs_origin_name(cp->flags), (cp->timer.expires-jiffies)/HZ); else #endif seq_printf(seq, "%-3s %08X %04X %08X %04X " |
f18ae7206 ipvs: use the new... |
1145 1146 |
"%s %04X %-11s %-6s %7lu ", |
7a4fbb1fa [IPVS]: Flag sync... |
1147 |
ip_vs_proto_name(cp->protocol), |
e7ade46a5 IPVS: Change IPVS... |
1148 1149 |
ntohl(cp->caddr.ip), ntohs(cp->cport), ntohl(cp->vaddr.ip), ntohs(cp->vport), |
f18ae7206 ipvs: use the new... |
1150 |
dbuf, ntohs(cp->dport), |
7a4fbb1fa [IPVS]: Flag sync... |
1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 |
ip_vs_state_name(cp->protocol, cp->state), ip_vs_origin_name(cp->flags), (cp->timer.expires-jiffies)/HZ); } return 0; } static const struct seq_operations ip_vs_conn_sync_seq_ops = { .start = ip_vs_conn_seq_start, .next = ip_vs_conn_seq_next, .stop = ip_vs_conn_seq_stop, .show = ip_vs_conn_sync_seq_show, }; static int ip_vs_conn_sync_open(struct inode *inode, struct file *file) { |
6e67e586e IPVS: netns, conn... |
1167 1168 |
return seq_open_net(inode, file, &ip_vs_conn_sync_seq_ops, sizeof(struct ip_vs_iter_state)); |
7a4fbb1fa [IPVS]: Flag sync... |
1169 1170 1171 1172 1173 1174 1175 |
} static const struct file_operations ip_vs_conn_sync_fops = { .owner = THIS_MODULE, .open = ip_vs_conn_sync_open, .read = seq_read, .llseek = seq_lseek, |
0f08190fe IPVS: fix netns i... |
1176 |
.release = seq_release_net, |
7a4fbb1fa [IPVS]: Flag sync... |
1177 |
}; |
1da177e4c Linux-2.6.12-rc2 |
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 |
#endif /* * Randomly drop connection entries before running out of memory */ static inline int todrop_entry(struct ip_vs_conn *cp) { /* * The drop rate array needs tuning for real environments. * Called from timer bh only => no locking */ |
9b5b5cff9 [NET]: Add const ... |
1190 |
static const char todrop_rate[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; |
1da177e4c Linux-2.6.12-rc2 |
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 |
static char todrop_counter[9] = {0}; int i; /* if the conn entry hasn't lasted for 60 seconds, don't drop it. This will leave enough time for normal connection to get through. */ if (time_before(cp->timeout + jiffies, cp->timer.expires + 60*HZ)) return 0; /* Don't drop the entry if its number of incoming packets is not located in [0, 8] */ i = atomic_read(&cp->in_pkts); if (i > 8 || i < 0) return 0; if (!todrop_rate[i]) return 0; if (--todrop_counter[i] > 0) return 0; todrop_counter[i] = todrop_rate[i]; return 1; } |
698e2a8dc ipvs: make drop_e... |
1211 1212 1213 1214 1215 1216 1217 1218 1219 |
static inline bool ip_vs_conn_ops_mode(struct ip_vs_conn *cp) { struct ip_vs_service *svc; if (!cp->dest) return false; svc = rcu_dereference(cp->dest->svc); return svc && (svc->flags & IP_VS_SVC_F_ONEPACKET); } |
af9debd46 [IPVS]: Add and r... |
1220 |
/* Called from keventd and must protect itself from softirqs */ |
423b55954 ipvs: Pass ipvs n... |
1221 |
void ip_vs_random_dropentry(struct netns_ipvs *ipvs) |
1da177e4c Linux-2.6.12-rc2 |
1222 1223 |
{ int idx; |
088339a57 ipvs: convert con... |
1224 |
struct ip_vs_conn *cp, *cp_c; |
1da177e4c Linux-2.6.12-rc2 |
1225 |
|
a38e5e230 ipvs: use cond_re... |
1226 |
rcu_read_lock(); |
1da177e4c Linux-2.6.12-rc2 |
1227 1228 1229 |
/* * Randomly scan 1/32 of the whole table every second */ |
6f7edb488 IPVS: Allow boot ... |
1230 |
for (idx = 0; idx < (ip_vs_conn_tab_size>>5); idx++) { |
63862b5be net: replace macr... |
1231 |
unsigned int hash = prandom_u32() & ip_vs_conn_tab_mask; |
1da177e4c Linux-2.6.12-rc2 |
1232 |
|
088339a57 ipvs: convert con... |
1233 |
hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[hash], c_list) { |
423b55954 ipvs: Pass ipvs n... |
1234 |
if (cp->ipvs != ipvs) |
f6340ee0c IPVS: netns, defe... |
1235 |
continue; |
698e2a8dc ipvs: make drop_e... |
1236 1237 1238 1239 1240 1241 1242 1243 |
if (cp->flags & IP_VS_CONN_F_TEMPLATE) { if (atomic_read(&cp->n_control) || !ip_vs_conn_ops_mode(cp)) continue; else /* connection template of OPS */ goto try_drop; } |
1da177e4c Linux-2.6.12-rc2 |
1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 |
if (cp->protocol == IPPROTO_TCP) { switch(cp->state) { case IP_VS_TCP_S_SYN_RECV: case IP_VS_TCP_S_SYNACK: break; case IP_VS_TCP_S_ESTABLISHED: if (todrop_entry(cp)) break; continue; default: continue; } |
acaac5d8b ipvs: drop SCTP c... |
1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 |
} else if (cp->protocol == IPPROTO_SCTP) { switch (cp->state) { case IP_VS_SCTP_S_INIT1: case IP_VS_SCTP_S_INIT: break; case IP_VS_SCTP_S_ESTABLISHED: if (todrop_entry(cp)) break; continue; default: continue; } |
1da177e4c Linux-2.6.12-rc2 |
1270 |
} else { |
698e2a8dc ipvs: make drop_e... |
1271 |
try_drop: |
1da177e4c Linux-2.6.12-rc2 |
1272 1273 1274 |
if (!todrop_entry(cp)) continue; } |
1da177e4c Linux-2.6.12-rc2 |
1275 1276 1277 |
IP_VS_DBG(4, "del connection "); ip_vs_conn_expire_now(cp); |
088339a57 ipvs: convert con... |
1278 1279 1280 |
cp_c = cp->control; /* cp->control is valid only with reference to cp */ if (cp_c && __ip_vs_conn_get(cp)) { |
1da177e4c Linux-2.6.12-rc2 |
1281 1282 |
IP_VS_DBG(4, "del conn template "); |
088339a57 ipvs: convert con... |
1283 1284 |
ip_vs_conn_expire_now(cp_c); __ip_vs_conn_put(cp); |
1da177e4c Linux-2.6.12-rc2 |
1285 |
} |
1da177e4c Linux-2.6.12-rc2 |
1286 |
} |
a38e5e230 ipvs: use cond_re... |
1287 |
cond_resched_rcu(); |
1da177e4c Linux-2.6.12-rc2 |
1288 |
} |
a38e5e230 ipvs: use cond_re... |
1289 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
1290 1291 1292 1293 1294 1295 |
} /* * Flush all the connection entries in the ip_vs_conn_tab */ |
d889717aa ipvs: Pass ipvs n... |
1296 |
static void ip_vs_conn_flush(struct netns_ipvs *ipvs) |
1da177e4c Linux-2.6.12-rc2 |
1297 1298 |
{ int idx; |
088339a57 ipvs: convert con... |
1299 |
struct ip_vs_conn *cp, *cp_c; |
1da177e4c Linux-2.6.12-rc2 |
1300 |
|
a0840e2e1 IPVS: netns, ip_v... |
1301 |
flush_again: |
a38e5e230 ipvs: use cond_re... |
1302 |
rcu_read_lock(); |
6f7edb488 IPVS: Allow boot ... |
1303 |
for (idx = 0; idx < ip_vs_conn_tab_size; idx++) { |
1da177e4c Linux-2.6.12-rc2 |
1304 |
|
088339a57 ipvs: convert con... |
1305 |
hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[idx], c_list) { |
58dbc6f26 ipvs: Store ipvs ... |
1306 |
if (cp->ipvs != ipvs) |
6e67e586e IPVS: netns, conn... |
1307 |
continue; |
1da177e4c Linux-2.6.12-rc2 |
1308 1309 1310 |
IP_VS_DBG(4, "del connection "); ip_vs_conn_expire_now(cp); |
088339a57 ipvs: convert con... |
1311 1312 1313 |
cp_c = cp->control; /* cp->control is valid only with reference to cp */ if (cp_c && __ip_vs_conn_get(cp)) { |
1da177e4c Linux-2.6.12-rc2 |
1314 1315 |
IP_VS_DBG(4, "del conn template "); |
088339a57 ipvs: convert con... |
1316 1317 |
ip_vs_conn_expire_now(cp_c); __ip_vs_conn_put(cp); |
1da177e4c Linux-2.6.12-rc2 |
1318 |
} |
1da177e4c Linux-2.6.12-rc2 |
1319 |
} |
a38e5e230 ipvs: use cond_re... |
1320 |
cond_resched_rcu(); |
1da177e4c Linux-2.6.12-rc2 |
1321 |
} |
a38e5e230 ipvs: use cond_re... |
1322 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
1323 1324 1325 |
/* the counter may be not NULL, because maybe some conn entries are run by slow timer handler or unhashed but still referred */ |
6e67e586e IPVS: netns, conn... |
1326 |
if (atomic_read(&ipvs->conn_count) != 0) { |
1da177e4c Linux-2.6.12-rc2 |
1327 1328 1329 1330 |
schedule(); goto flush_again; } } |
61b1ab458 IPVS: netns, add ... |
1331 1332 1333 |
/* * per netns init and exit */ |
2f3edc6a5 ipvs: Pass ipvs n... |
1334 |
int __net_init ip_vs_conn_net_init(struct netns_ipvs *ipvs) |
61b1ab458 IPVS: netns, add ... |
1335 |
{ |
6e67e586e IPVS: netns, conn... |
1336 |
atomic_set(&ipvs->conn_count, 0); |
1da177e4c Linux-2.6.12-rc2 |
1337 |
|
92240e8dc ipvs: Remove poss... |
1338 1339 1340 |
proc_create("ip_vs_conn", 0, ipvs->net->proc_net, &ip_vs_conn_fops); proc_create("ip_vs_conn_sync", 0, ipvs->net->proc_net, &ip_vs_conn_sync_fops); |
61b1ab458 IPVS: netns, add ... |
1341 1342 |
return 0; } |
2f3edc6a5 ipvs: Pass ipvs n... |
1343 |
void __net_exit ip_vs_conn_net_cleanup(struct netns_ipvs *ipvs) |
61b1ab458 IPVS: netns, add ... |
1344 |
{ |
6e67e586e IPVS: netns, conn... |
1345 |
/* flush all the connection entries first */ |
d889717aa ipvs: Pass ipvs n... |
1346 |
ip_vs_conn_flush(ipvs); |
92240e8dc ipvs: Remove poss... |
1347 1348 |
remove_proc_entry("ip_vs_conn", ipvs->net->proc_net); remove_proc_entry("ip_vs_conn_sync", ipvs->net->proc_net); |
61b1ab458 IPVS: netns, add ... |
1349 |
} |
1da177e4c Linux-2.6.12-rc2 |
1350 |
|
048cf48b8 ipvs: Annotate in... |
1351 |
int __init ip_vs_conn_init(void) |
1da177e4c Linux-2.6.12-rc2 |
1352 1353 |
{ int idx; |
6f7edb488 IPVS: Allow boot ... |
1354 1355 1356 |
/* Compute size and mask */ ip_vs_conn_tab_size = 1 << ip_vs_conn_tab_bits; ip_vs_conn_tab_mask = ip_vs_conn_tab_size - 1; |
1da177e4c Linux-2.6.12-rc2 |
1357 1358 1359 |
/* * Allocate the connection hash table and initialize its list heads */ |
731109e78 ipvs: use hlist i... |
1360 |
ip_vs_conn_tab = vmalloc(ip_vs_conn_tab_size * sizeof(*ip_vs_conn_tab)); |
1da177e4c Linux-2.6.12-rc2 |
1361 1362 1363 1364 1365 1366 |
if (!ip_vs_conn_tab) return -ENOMEM; /* Allocate ip_vs_conn slab cache */ ip_vs_conn_cachep = kmem_cache_create("ip_vs_conn", sizeof(struct ip_vs_conn), 0, |
20c2df83d mm: Remove slab d... |
1367 |
SLAB_HWCACHE_ALIGN, NULL); |
1da177e4c Linux-2.6.12-rc2 |
1368 1369 1370 1371 |
if (!ip_vs_conn_cachep) { vfree(ip_vs_conn_tab); return -ENOMEM; } |
1e3e238e9 IPVS: use pr_err ... |
1372 1373 1374 |
pr_info("Connection hash table configured " "(size=%d, memory=%ldKbytes) ", |
6f7edb488 IPVS: Allow boot ... |
1375 1376 |
ip_vs_conn_tab_size, (long)(ip_vs_conn_tab_size*sizeof(struct list_head))/1024); |
1da177e4c Linux-2.6.12-rc2 |
1377 1378 1379 |
IP_VS_DBG(0, "Each connection entry needs %Zd bytes at least ", sizeof(struct ip_vs_conn)); |
731109e78 ipvs: use hlist i... |
1380 1381 |
for (idx = 0; idx < ip_vs_conn_tab_size; idx++) INIT_HLIST_HEAD(&ip_vs_conn_tab[idx]); |
1da177e4c Linux-2.6.12-rc2 |
1382 1383 |
for (idx = 0; idx < CT_LOCKARRAY_SIZE; idx++) { |
088339a57 ipvs: convert con... |
1384 |
spin_lock_init(&__ip_vs_conntbl_lock_array[idx].l); |
1da177e4c Linux-2.6.12-rc2 |
1385 |
} |
1da177e4c Linux-2.6.12-rc2 |
1386 1387 |
/* calculate the random value for connection hash */ get_random_bytes(&ip_vs_conn_rnd, sizeof(ip_vs_conn_rnd)); |
7a4f0761f IPVS: init and cl... |
1388 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1389 |
} |
1da177e4c Linux-2.6.12-rc2 |
1390 1391 |
void ip_vs_conn_cleanup(void) { |
088339a57 ipvs: convert con... |
1392 1393 |
/* Wait all ip_vs_conn_rcu_free() callbacks to complete */ rcu_barrier(); |
1da177e4c Linux-2.6.12-rc2 |
1394 1395 |
/* Release the empty cache */ kmem_cache_destroy(ip_vs_conn_cachep); |
1da177e4c Linux-2.6.12-rc2 |
1396 1397 |
vfree(ip_vs_conn_tab); } |