Blame view

net/netfilter/ipvs/ip_vs_core.c 56.9 KB
1da177e4c   Linus Torvalds   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   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   * 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.
   *
   * Changes:
   *	Paul `Rusty' Russell		properly handle non-linear skbs
6869c4d8e   Harald Welte   [NETFILTER]: redu...
23
   *	Harald Welte			don't use nfcache
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
   *
   */
9aada7ac0   Hannes Eder   IPVS: use pr_fmt
26
27
  #define KMSG_COMPONENT "IPVS"
  #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/ip.h>
  #include <linux/tcp.h>
2906f66a5   Venkata Mohan Reddy   ipvs: SCTP Traspo...
32
  #include <linux/sctp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  #include <linux/icmp.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
34
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
39
40
  
  #include <net/ip.h>
  #include <net/tcp.h>
  #include <net/udp.h>
  #include <net/icmp.h>                   /* for icmp_send */
  #include <net/route.h>
2c70b5196   Stephen Rothwell   IPVS: include net...
41
  #include <net/ip6_checksum.h>
61b1ab458   Hans Schillstrom   IPVS: netns, add ...
42
  #include <net/netns/generic.h>		/* net_generic() */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
  
  #include <linux/netfilter.h>
  #include <linux/netfilter_ipv4.h>
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
46
47
48
  #ifdef CONFIG_IP_VS_IPV6
  #include <net/ipv6.h>
  #include <linux/netfilter_ipv6.h>
489fdedae   Julian Anastasov   ipvs: stop ICMP f...
49
  #include <net/ip6_route.h>
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
50
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
53
54
55
  #include <net/ip_vs.h>
  
  
  EXPORT_SYMBOL(register_ip_vs_scheduler);
  EXPORT_SYMBOL(unregister_ip_vs_scheduler);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
59
60
61
62
63
64
65
66
  EXPORT_SYMBOL(ip_vs_proto_name);
  EXPORT_SYMBOL(ip_vs_conn_new);
  EXPORT_SYMBOL(ip_vs_conn_in_get);
  EXPORT_SYMBOL(ip_vs_conn_out_get);
  #ifdef CONFIG_IP_VS_PROTO_TCP
  EXPORT_SYMBOL(ip_vs_tcp_conn_listen);
  #endif
  EXPORT_SYMBOL(ip_vs_conn_put);
  #ifdef CONFIG_IP_VS_DEBUG
  EXPORT_SYMBOL(ip_vs_get_debug_level);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67

b962abdc6   Julian Anastasov   ipvs: fix some sp...
68
  static int ip_vs_net_id __read_mostly;
61b1ab458   Hans Schillstrom   IPVS: netns, add ...
69
70
  /* netns cnt used for uniqueness */
  static atomic_t ipvs_netns_cnt = ATOMIC_INIT(0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
  
  /* ID used in ICMP lookups */
  #define icmp_id(icmph)          (((icmph)->un).echo.id)
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
74
  #define icmpv6_id(icmph)        (icmph->icmp6_dataun.u_echo.identifier)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75

95c961747   Eric Dumazet   net: cleanup unsi...
76
  const char *ip_vs_proto_name(unsigned int proto)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
80
81
82
83
84
85
86
  {
  	static char buf[20];
  
  	switch (proto) {
  	case IPPROTO_IP:
  		return "IP";
  	case IPPROTO_UDP:
  		return "UDP";
  	case IPPROTO_TCP:
  		return "TCP";
2906f66a5   Venkata Mohan Reddy   ipvs: SCTP Traspo...
87
88
  	case IPPROTO_SCTP:
  		return "SCTP";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
  	case IPPROTO_ICMP:
  		return "ICMP";
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
91
92
93
94
  #ifdef CONFIG_IP_VS_IPV6
  	case IPPROTO_ICMPV6:
  		return "ICMPv6";
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
  	default:
1404c3ab9   Masanari Iida   netfilter: Fix fo...
96
  		sprintf(buf, "IP_%u", proto);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  		return buf;
  	}
  }
  
  void ip_vs_init_hash_table(struct list_head *table, int rows)
  {
  	while (--rows >= 0)
  		INIT_LIST_HEAD(&table[rows]);
  }
  
  static inline void
  ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
  {
  	struct ip_vs_dest *dest = cp->dest;
7c08d78e6   Eric W. Biederman   ipvs: Better deri...
111
  	struct netns_ipvs *ipvs = cp->ipvs;
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
112

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
  	if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
114
  		struct ip_vs_cpu_stats *s;
bcbde4c0a   Julian Anastasov   ipvs: make the se...
115
  		struct ip_vs_service *svc;
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
116
117
  
  		s = this_cpu_ptr(dest->stats.cpustats);
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
118
  		u64_stats_update_begin(&s->syncp);
cd67cd5eb   Julian Anastasov   ipvs: use 64-bit ...
119
120
  		s->cnt.inpkts++;
  		s->cnt.inbytes += skb->len;
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
121
  		u64_stats_update_end(&s->syncp);
bcbde4c0a   Julian Anastasov   ipvs: make the se...
122
123
124
  		rcu_read_lock();
  		svc = rcu_dereference(dest->svc);
  		s = this_cpu_ptr(svc->stats.cpustats);
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
125
  		u64_stats_update_begin(&s->syncp);
cd67cd5eb   Julian Anastasov   ipvs: use 64-bit ...
126
127
  		s->cnt.inpkts++;
  		s->cnt.inbytes += skb->len;
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
128
  		u64_stats_update_end(&s->syncp);
bcbde4c0a   Julian Anastasov   ipvs: make the se...
129
  		rcu_read_unlock();
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
130

2a0751af0   Julian Anastasov   ipvs: reorganize ...
131
  		s = this_cpu_ptr(ipvs->tot_stats.cpustats);
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
132
  		u64_stats_update_begin(&s->syncp);
cd67cd5eb   Julian Anastasov   ipvs: use 64-bit ...
133
134
  		s->cnt.inpkts++;
  		s->cnt.inbytes += skb->len;
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
135
  		u64_stats_update_end(&s->syncp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
139
140
141
142
143
  	}
  }
  
  
  static inline void
  ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
  {
  	struct ip_vs_dest *dest = cp->dest;
7c08d78e6   Eric W. Biederman   ipvs: Better deri...
144
  	struct netns_ipvs *ipvs = cp->ipvs;
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
145

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  	if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
147
  		struct ip_vs_cpu_stats *s;
bcbde4c0a   Julian Anastasov   ipvs: make the se...
148
  		struct ip_vs_service *svc;
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
149
150
  
  		s = this_cpu_ptr(dest->stats.cpustats);
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
151
  		u64_stats_update_begin(&s->syncp);
cd67cd5eb   Julian Anastasov   ipvs: use 64-bit ...
152
153
  		s->cnt.outpkts++;
  		s->cnt.outbytes += skb->len;
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
154
  		u64_stats_update_end(&s->syncp);
bcbde4c0a   Julian Anastasov   ipvs: make the se...
155
156
157
  		rcu_read_lock();
  		svc = rcu_dereference(dest->svc);
  		s = this_cpu_ptr(svc->stats.cpustats);
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
158
  		u64_stats_update_begin(&s->syncp);
cd67cd5eb   Julian Anastasov   ipvs: use 64-bit ...
159
160
  		s->cnt.outpkts++;
  		s->cnt.outbytes += skb->len;
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
161
  		u64_stats_update_end(&s->syncp);
bcbde4c0a   Julian Anastasov   ipvs: make the se...
162
  		rcu_read_unlock();
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
163

2a0751af0   Julian Anastasov   ipvs: reorganize ...
164
  		s = this_cpu_ptr(ipvs->tot_stats.cpustats);
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
165
  		u64_stats_update_begin(&s->syncp);
cd67cd5eb   Julian Anastasov   ipvs: use 64-bit ...
166
167
  		s->cnt.outpkts++;
  		s->cnt.outbytes += skb->len;
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
168
  		u64_stats_update_end(&s->syncp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
173
174
175
  	}
  }
  
  
  static inline void
  ip_vs_conn_stats(struct ip_vs_conn *cp, struct ip_vs_service *svc)
  {
3109d2f2d   Eric W. Biederman   ipvs: Store ipvs ...
176
  	struct netns_ipvs *ipvs = svc->ipvs;
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
177
  	struct ip_vs_cpu_stats *s;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178

b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
179
  	s = this_cpu_ptr(cp->dest->stats.cpustats);
cd67cd5eb   Julian Anastasov   ipvs: use 64-bit ...
180
181
182
  	u64_stats_update_begin(&s->syncp);
  	s->cnt.conns++;
  	u64_stats_update_end(&s->syncp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183

b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
184
  	s = this_cpu_ptr(svc->stats.cpustats);
cd67cd5eb   Julian Anastasov   ipvs: use 64-bit ...
185
186
187
  	u64_stats_update_begin(&s->syncp);
  	s->cnt.conns++;
  	u64_stats_update_end(&s->syncp);
b17fc9963   Hans Schillstrom   IPVS: netns, ip_v...
188

2a0751af0   Julian Anastasov   ipvs: reorganize ...
189
  	s = this_cpu_ptr(ipvs->tot_stats.cpustats);
cd67cd5eb   Julian Anastasov   ipvs: use 64-bit ...
190
191
192
  	u64_stats_update_begin(&s->syncp);
  	s->cnt.conns++;
  	u64_stats_update_end(&s->syncp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
  }
4a516f110   Simon Horman   ipvs: Remove unus...
194
  static inline void
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
  ip_vs_set_state(struct ip_vs_conn *cp, int direction,
  		const struct sk_buff *skb,
9330419d9   Hans Schillstrom   IPVS: netns, use ...
197
  		struct ip_vs_proto_data *pd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
  {
4a516f110   Simon Horman   ipvs: Remove unus...
199
200
  	if (likely(pd->pp->state_transition))
  		pd->pp->state_transition(cp, direction, skb, pd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
  }
a5959d53d   Hans Schillstrom   IPVS: Handle Sche...
202
  static inline int
85999283a   Simon Horman   IPVS: Add struct ...
203
204
205
206
207
208
  ip_vs_conn_fill_param_persist(const struct ip_vs_service *svc,
  			      struct sk_buff *skb, int protocol,
  			      const union nf_inet_addr *caddr, __be16 cport,
  			      const union nf_inet_addr *vaddr, __be16 vport,
  			      struct ip_vs_conn_param *p)
  {
3109d2f2d   Eric W. Biederman   ipvs: Store ipvs ...
209
  	ip_vs_conn_fill_param(svc->ipvs, svc->af, protocol, caddr, cport, vaddr,
6e67e586e   Hans Schillstrom   IPVS: netns, conn...
210
  			      vport, p);
ceec4c381   Julian Anastasov   ipvs: convert ser...
211
  	p->pe = rcu_dereference(svc->pe);
85999283a   Simon Horman   IPVS: Add struct ...
212
  	if (p->pe && p->pe->fill_param)
a5959d53d   Hans Schillstrom   IPVS: Handle Sche...
213
214
215
  		return p->pe->fill_param(p, skb);
  
  	return 0;
85999283a   Simon Horman   IPVS: Add struct ...
216
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
220
221
222
223
224
225
226
  /*
   *  IPVS persistent scheduling function
   *  It creates a connection entry according to its template if exists,
   *  or selects a server and creates a connection entry plus a template.
   *  Locking: we are svc user (svc->refcnt), so we hold all dests too
   *  Protocols supported: TCP, UDP
   */
  static struct ip_vs_conn *
  ip_vs_sched_persist(struct ip_vs_service *svc,
d4383f04d   Jesper Dangaard Brouer   ipvs: API change ...
227
228
  		    struct sk_buff *skb, __be16 src_port, __be16 dst_port,
  		    int *ignored, struct ip_vs_iphdr *iph)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
  {
  	struct ip_vs_conn *cp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
232
  	struct ip_vs_dest *dest;
  	struct ip_vs_conn *ct;
5b57a98c1   Simon Horman   IPVS: compact ip_...
233
  	__be16 dport = 0;		/* destination port to forward */
3575792e0   Julian Anastasov   ipvs: extend conn...
234
  	unsigned int flags;
f11017ec2   Simon Horman   IPVS: Add struct ...
235
  	struct ip_vs_conn_param param;
e0aac52e1   Simon Horman   ipvs: fix matchin...
236
  	const union nf_inet_addr fwmark = { .ip = htonl(svc->fwmark) };
28364a59f   Julius Volz   IPVS: Extend func...
237
238
  	union nf_inet_addr snet;	/* source network of the client,
  					   after masking */
ee78378f9   Alex Gartrell   ipvs: Make ip_vs_...
239
240
241
242
243
244
245
246
247
  	const union nf_inet_addr *src_addr, *dst_addr;
  
  	if (likely(!ip_vs_iph_inverse(iph))) {
  		src_addr = &iph->saddr;
  		dst_addr = &iph->daddr;
  	} else {
  		src_addr = &iph->daddr;
  		dst_addr = &iph->saddr;
  	}
cd17f9ed0   Julius Volz   IPVS: Extend sche...
248

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
  	/* Mask saddr with the netmask to adjust template granularity */
cd17f9ed0   Julius Volz   IPVS: Extend sche...
250
251
  #ifdef CONFIG_IP_VS_IPV6
  	if (svc->af == AF_INET6)
ee78378f9   Alex Gartrell   ipvs: Make ip_vs_...
252
  		ipv6_addr_prefix(&snet.in6, &src_addr->in6,
0a925864c   Julian Anastasov   ipvs: fix sparse ...
253
  				 (__force __u32) svc->netmask);
cd17f9ed0   Julius Volz   IPVS: Extend sche...
254
255
  	else
  #endif
ee78378f9   Alex Gartrell   ipvs: Make ip_vs_...
256
  		snet.ip = src_addr->ip & svc->netmask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257

cd17f9ed0   Julius Volz   IPVS: Extend sche...
258
259
260
  	IP_VS_DBG_BUF(6, "p-schedule: src %s:%u dest %s:%u "
  		      "mnet %s
  ",
ee78378f9   Alex Gartrell   ipvs: Make ip_vs_...
261
262
  		      IP_VS_DBG_ADDR(svc->af, src_addr), ntohs(src_port),
  		      IP_VS_DBG_ADDR(svc->af, dst_addr), ntohs(dst_port),
cd17f9ed0   Julius Volz   IPVS: Extend sche...
263
  		      IP_VS_DBG_ADDR(svc->af, &snet));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
265
266
267
268
269
270
271
272
273
274
275
276
277
  
  	/*
  	 * As far as we know, FTP is a very complicated network protocol, and
  	 * it uses control connection and data connections. For active FTP,
  	 * FTP server initialize data connection to the client, its source port
  	 * is often 20. For passive FTP, FTP server tells the clients the port
  	 * that it passively listens to,  and the client issues the data
  	 * connection. In the tunneling or direct routing mode, the load
  	 * balancer is on the client-to-server half of connection, the port
  	 * number is unknown to the load balancer. So, a conn template like
  	 * <caddr, 0, vaddr, 0, daddr, 0> is created for persistent FTP
  	 * service, and a template like <caddr, 0, vaddr, vport, daddr, dport>
  	 * is created for other persistent services.
  	 */
5b57a98c1   Simon Horman   IPVS: compact ip_...
278
  	{
d4383f04d   Jesper Dangaard Brouer   ipvs: API change ...
279
  		int protocol = iph->protocol;
ee78378f9   Alex Gartrell   ipvs: Make ip_vs_...
280
  		const union nf_inet_addr *vaddr = dst_addr;
f11017ec2   Simon Horman   IPVS: Add struct ...
281
  		__be16 vport = 0;
ce144f249   Hans Schillstrom   IPVS: Split ports...
282
  		if (dst_port == svc->port) {
5b57a98c1   Simon Horman   IPVS: compact ip_...
283
284
285
286
  			/* non-FTP template:
  			 * <protocol, caddr, 0, vaddr, vport, daddr, dport>
  			 * FTP template:
  			 * <protocol, caddr, 0, vaddr, 0, daddr, 0>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
  			 */
  			if (svc->port != FTPPORT)
ce144f249   Hans Schillstrom   IPVS: Split ports...
289
  				vport = dst_port;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  		} else {
5b57a98c1   Simon Horman   IPVS: compact ip_...
291
292
293
294
295
296
  			/* Note: persistent fwmark-based services and
  			 * persistent port zero service are handled here.
  			 * fwmark template:
  			 * <IPPROTO_IP,caddr,0,fwmark,0,daddr,0>
  			 * port zero template:
  			 * <protocol,caddr,0,vaddr,0,daddr,0>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
  			 */
28364a59f   Julius Volz   IPVS: Extend func...
298
  			if (svc->fwmark) {
5b57a98c1   Simon Horman   IPVS: compact ip_...
299
300
301
  				protocol = IPPROTO_IP;
  				vaddr = &fwmark;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
  		}
a5959d53d   Hans Schillstrom   IPVS: Handle Sche...
303
304
305
306
307
308
  		/* return *ignored = -1 so NF_DROP can be used */
  		if (ip_vs_conn_fill_param_persist(svc, skb, protocol, &snet, 0,
  						  vaddr, vport, &param) < 0) {
  			*ignored = -1;
  			return NULL;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
  	}
5b57a98c1   Simon Horman   IPVS: compact ip_...
310
  	/* Check if a template already exists */
f11017ec2   Simon Horman   IPVS: Add struct ...
311
  	ct = ip_vs_ct_in_get(&param);
5b57a98c1   Simon Horman   IPVS: compact ip_...
312
  	if (!ct || !ip_vs_check_template(ct)) {
ceec4c381   Julian Anastasov   ipvs: convert ser...
313
  		struct ip_vs_scheduler *sched;
a5959d53d   Hans Schillstrom   IPVS: Handle Sche...
314
315
  		/*
  		 * No template found or the dest of the connection
5b57a98c1   Simon Horman   IPVS: compact ip_...
316
  		 * template is not available.
a5959d53d   Hans Schillstrom   IPVS: Handle Sche...
317
  		 * return *ignored=0 i.e. ICMP and NF_DROP
5b57a98c1   Simon Horman   IPVS: compact ip_...
318
  		 */
ceec4c381   Julian Anastasov   ipvs: convert ser...
319
  		sched = rcu_dereference(svc->scheduler);
05f00505a   Julian Anastasov   ipvs: fix crash i...
320
321
322
323
324
325
326
  		if (sched) {
  			/* read svc->sched_data after svc->scheduler */
  			smp_rmb();
  			dest = sched->schedule(svc, skb, iph);
  		} else {
  			dest = NULL;
  		}
5b57a98c1   Simon Horman   IPVS: compact ip_...
327
328
329
  		if (!dest) {
  			IP_VS_DBG(1, "p-schedule: no dest found.
  ");
85999283a   Simon Horman   IPVS: Add struct ...
330
  			kfree(param.pe_data);
a5959d53d   Hans Schillstrom   IPVS: Handle Sche...
331
  			*ignored = 0;
5b57a98c1   Simon Horman   IPVS: compact ip_...
332
333
  			return NULL;
  		}
ce144f249   Hans Schillstrom   IPVS: Split ports...
334
  		if (dst_port == svc->port && svc->port != FTPPORT)
5b57a98c1   Simon Horman   IPVS: compact ip_...
335
  			dport = dest->port;
85999283a   Simon Horman   IPVS: Add struct ...
336
337
338
339
  		/* Create a template
  		 * This adds param.pe_data to the template,
  		 * and thus param.pe_data will be destroyed
  		 * when the template expires */
ba38528aa   Alex Gartrell   ipvs: Supply dest...
340
  		ct = ip_vs_conn_new(&param, dest->af, &dest->addr, dport,
0e051e683   Hans Schillstrom   IPVS: Backup, Pre...
341
  				    IP_VS_CONN_F_TEMPLATE, dest, skb->mark);
85999283a   Simon Horman   IPVS: Add struct ...
342
343
  		if (ct == NULL) {
  			kfree(param.pe_data);
a5959d53d   Hans Schillstrom   IPVS: Handle Sche...
344
  			*ignored = -1;
5b57a98c1   Simon Horman   IPVS: compact ip_...
345
  			return NULL;
85999283a   Simon Horman   IPVS: Add struct ...
346
  		}
5b57a98c1   Simon Horman   IPVS: compact ip_...
347
348
  
  		ct->timeout = svc->timeout;
85999283a   Simon Horman   IPVS: Add struct ...
349
  	} else {
5b57a98c1   Simon Horman   IPVS: compact ip_...
350
351
  		/* set destination with the found template */
  		dest = ct->dest;
85999283a   Simon Horman   IPVS: Add struct ...
352
353
  		kfree(param.pe_data);
  	}
5b57a98c1   Simon Horman   IPVS: compact ip_...
354

ce144f249   Hans Schillstrom   IPVS: Split ports...
355
  	dport = dst_port;
5b57a98c1   Simon Horman   IPVS: compact ip_...
356
357
  	if (dport == svc->port && dest->port)
  		dport = dest->port;
26ec037f9   Nick Chalk   IPVS: one-packet ...
358
  	flags = (svc->flags & IP_VS_SVC_F_ONEPACKET
d4383f04d   Jesper Dangaard Brouer   ipvs: API change ...
359
  		 && iph->protocol == IPPROTO_UDP) ?
26ec037f9   Nick Chalk   IPVS: one-packet ...
360
  		IP_VS_CONN_F_ONE_PACKET : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
363
  	/*
  	 *    Create a new connection according to the template
  	 */
3109d2f2d   Eric W. Biederman   ipvs: Store ipvs ...
364
  	ip_vs_conn_fill_param(svc->ipvs, svc->af, iph->protocol, src_addr,
ee78378f9   Alex Gartrell   ipvs: Make ip_vs_...
365
  			      src_port, dst_addr, dst_port, &param);
ce144f249   Hans Schillstrom   IPVS: Split ports...
366

ba38528aa   Alex Gartrell   ipvs: Supply dest...
367
368
  	cp = ip_vs_conn_new(&param, dest->af, &dest->addr, dport, flags, dest,
  			    skb->mark);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
370
  	if (cp == NULL) {
  		ip_vs_conn_put(ct);
a5959d53d   Hans Schillstrom   IPVS: Handle Sche...
371
  		*ignored = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
  		return NULL;
  	}
  
  	/*
  	 *    Add its control
  	 */
  	ip_vs_control_add(cp, ct);
  	ip_vs_conn_put(ct);
  
  	ip_vs_conn_stats(cp, svc);
  	return cp;
  }
  
  
  /*
   *  IPVS main scheduling function
   *  It selects a server according to the virtual service, and
   *  creates a connection entry.
   *  Protocols supported: TCP, UDP
a5959d53d   Hans Schillstrom   IPVS: Handle Sche...
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
   *
   *  Usage of *ignored
   *
   * 1 :   protocol tried to schedule (eg. on SYN), found svc but the
   *       svc/scheduler decides that this packet should be accepted with
   *       NF_ACCEPT because it must not be scheduled.
   *
   * 0 :   scheduler can not find destination, so try bypass or
   *       return ICMP and then NF_DROP (ip_vs_leave).
   *
   * -1 :  scheduler tried to schedule but fatal error occurred, eg.
   *       ip_vs_conn_new failure (ENOMEM) or ip_vs_sip_fill_param
   *       failure such as missing Call-ID, ENOMEM on skb_linearize
   *       or pe_data. In this case we should return NF_DROP without
   *       any attempts to send ICMP with ip_vs_leave.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
   */
  struct ip_vs_conn *
190ecd27c   Julian Anastasov   ipvs: do not sche...
408
  ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,
d4383f04d   Jesper Dangaard Brouer   ipvs: API change ...
409
410
  	       struct ip_vs_proto_data *pd, int *ignored,
  	       struct ip_vs_iphdr *iph)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
  {
9330419d9   Hans Schillstrom   IPVS: netns, use ...
412
  	struct ip_vs_protocol *pp = pd->pp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
  	struct ip_vs_conn *cp = NULL;
ceec4c381   Julian Anastasov   ipvs: convert ser...
414
  	struct ip_vs_scheduler *sched;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
  	struct ip_vs_dest *dest;
ee78378f9   Alex Gartrell   ipvs: Make ip_vs_...
416
417
  	__be16 _ports[2], *pptr, cport, vport;
  	const void *caddr, *vaddr;
3575792e0   Julian Anastasov   ipvs: extend conn...
418
  	unsigned int flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419

190ecd27c   Julian Anastasov   ipvs: do not sche...
420
  	*ignored = 1;
2f74713d1   Jesper Dangaard Brouer   ipvs: Complete IP...
421
422
423
  	/*
  	 * IPv6 frags, only the first hit here.
  	 */
d4383f04d   Jesper Dangaard Brouer   ipvs: API change ...
424
  	pptr = frag_safe_skb_hp(skb, iph->len, sizeof(_ports), _ports, iph);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
  	if (pptr == NULL)
  		return NULL;
ee78378f9   Alex Gartrell   ipvs: Make ip_vs_...
427
428
429
430
431
432
433
434
435
436
437
  	if (likely(!ip_vs_iph_inverse(iph))) {
  		cport = pptr[0];
  		caddr = &iph->saddr;
  		vport = pptr[1];
  		vaddr = &iph->daddr;
  	} else {
  		cport = pptr[1];
  		caddr = &iph->daddr;
  		vport = pptr[0];
  		vaddr = &iph->saddr;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
  	/*
190ecd27c   Julian Anastasov   ipvs: do not sche...
439
440
441
442
443
  	 * FTPDATA needs this check when using local real server.
  	 * Never schedule Active FTPDATA connections from real server.
  	 * For LVS-NAT they must be already created. For other methods
  	 * with persistence the connection is created on SYN+ACK.
  	 */
ee78378f9   Alex Gartrell   ipvs: Make ip_vs_...
444
  	if (cport == FTPDATA) {
b0e010c52   Alex Gartrell   ipvs: replace ip_...
445
  		IP_VS_DBG_PKT(12, svc->af, pp, skb, iph->off,
0d79641a9   Julian Anastasov   ipvs: provide add...
446
  			      "Not scheduling FTPDATA");
190ecd27c   Julian Anastasov   ipvs: do not sche...
447
448
449
450
  		return NULL;
  	}
  
  	/*
a5959d53d   Hans Schillstrom   IPVS: Handle Sche...
451
  	 *    Do not schedule replies from local real server.
190ecd27c   Julian Anastasov   ipvs: do not sche...
452
  	 */
802c41adc   Alex Gartrell   ipvs: drop invers...
453
454
  	if ((!skb->dev || skb->dev->flags & IFF_LOOPBACK)) {
  		iph->hdr_flags ^= IP_VS_HDR_INVERSE;
ab1619764   Eric W. Biederman   ipvs: Pass ipvs i...
455
  		cp = pp->conn_in_get(svc->ipvs, svc->af, skb, iph);
802c41adc   Alex Gartrell   ipvs: drop invers...
456
457
458
459
460
461
462
463
464
  		iph->hdr_flags ^= IP_VS_HDR_INVERSE;
  
  		if (cp) {
  			IP_VS_DBG_PKT(12, svc->af, pp, skb, iph->off,
  				      "Not scheduling reply for existing"
  				      " connection");
  			__ip_vs_conn_put(cp);
  			return NULL;
  		}
190ecd27c   Julian Anastasov   ipvs: do not sche...
465
466
467
  	}
  
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
  	 *    Persistent service
  	 */
a5959d53d   Hans Schillstrom   IPVS: Handle Sche...
470
  	if (svc->flags & IP_VS_SVC_F_PERSISTENT)
ee78378f9   Alex Gartrell   ipvs: Make ip_vs_...
471
  		return ip_vs_sched_persist(svc, skb, cport, vport, ignored,
d4383f04d   Jesper Dangaard Brouer   ipvs: API change ...
472
  					   iph);
a5959d53d   Hans Schillstrom   IPVS: Handle Sche...
473
474
  
  	*ignored = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
476
477
478
  
  	/*
  	 *    Non-persistent service
  	 */
ee78378f9   Alex Gartrell   ipvs: Make ip_vs_...
479
  	if (!svc->fwmark && vport != svc->port) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
  		if (!svc->port)
1e3e238e9   Hannes Eder   IPVS: use pr_err ...
481
482
483
484
  			pr_err("Schedule: port zero only supported "
  			       "in persistent services, "
  			       "check your ipvs configuration
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
486
  		return NULL;
  	}
ceec4c381   Julian Anastasov   ipvs: convert ser...
487
  	sched = rcu_dereference(svc->scheduler);
05f00505a   Julian Anastasov   ipvs: fix crash i...
488
489
490
491
492
493
494
  	if (sched) {
  		/* read svc->sched_data after svc->scheduler */
  		smp_rmb();
  		dest = sched->schedule(svc, skb, iph);
  	} else {
  		dest = NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
496
497
498
499
  	if (dest == NULL) {
  		IP_VS_DBG(1, "Schedule: no dest found.
  ");
  		return NULL;
  	}
26ec037f9   Nick Chalk   IPVS: one-packet ...
500
  	flags = (svc->flags & IP_VS_SVC_F_ONEPACKET
d4383f04d   Jesper Dangaard Brouer   ipvs: API change ...
501
  		 && iph->protocol == IPPROTO_UDP) ?
26ec037f9   Nick Chalk   IPVS: one-packet ...
502
  		IP_VS_CONN_F_ONE_PACKET : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
505
  	/*
  	 *    Create a connection entry.
  	 */
f11017ec2   Simon Horman   IPVS: Add struct ...
506
507
  	{
  		struct ip_vs_conn_param p;
6e67e586e   Hans Schillstrom   IPVS: netns, conn...
508

3109d2f2d   Eric W. Biederman   ipvs: Store ipvs ...
509
  		ip_vs_conn_fill_param(svc->ipvs, svc->af, iph->protocol,
ee78378f9   Alex Gartrell   ipvs: Make ip_vs_...
510
  				      caddr, cport, vaddr, vport, &p);
ba38528aa   Alex Gartrell   ipvs: Supply dest...
511
  		cp = ip_vs_conn_new(&p, dest->af, &dest->addr,
ee78378f9   Alex Gartrell   ipvs: Make ip_vs_...
512
  				    dest->port ? dest->port : vport,
0e051e683   Hans Schillstrom   IPVS: Backup, Pre...
513
  				    flags, dest, skb->mark);
a5959d53d   Hans Schillstrom   IPVS: Handle Sche...
514
515
  		if (!cp) {
  			*ignored = -1;
f11017ec2   Simon Horman   IPVS: Add struct ...
516
  			return NULL;
a5959d53d   Hans Schillstrom   IPVS: Handle Sche...
517
  		}
f11017ec2   Simon Horman   IPVS: Add struct ...
518
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519

cd17f9ed0   Julius Volz   IPVS: Extend sche...
520
521
522
523
  	IP_VS_DBG_BUF(6, "Schedule fwd:%c c:%s:%u v:%s:%u "
  		      "d:%s:%u conn->flags:%X conn->refcnt:%d
  ",
  		      ip_vs_fwd_tag(cp),
f18ae7206   Julian Anastasov   ipvs: use the new...
524
525
526
  		      IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport),
  		      IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
  		      IP_VS_DBG_ADDR(cp->daf, &cp->daddr), ntohs(cp->dport),
cd17f9ed0   Julius Volz   IPVS: Extend sche...
527
  		      cp->flags, atomic_read(&cp->refcnt));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
529
530
531
  
  	ip_vs_conn_stats(cp, svc);
  	return cp;
  }
0b7290212   Alex Gartrell   ipvs: Handle inve...
532
533
534
535
536
537
538
539
540
541
542
  #ifdef CONFIG_SYSCTL
  static inline int ip_vs_addr_is_unicast(struct net *net, int af,
  					union nf_inet_addr *addr)
  {
  #ifdef CONFIG_IP_VS_IPV6
  	if (af == AF_INET6)
  		return ipv6_addr_type(&addr->in6) & IPV6_ADDR_UNICAST;
  #endif
  	return (inet_addr_type(net, addr->ip) == RTN_UNICAST);
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
544
545
546
547
548
549
  
  /*
   *  Pass or drop the packet.
   *  Called by ip_vs_in, when the virtual service is available but
   *  no destination is available for a new connection.
   */
  int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
d4383f04d   Jesper Dangaard Brouer   ipvs: API change ...
550
  		struct ip_vs_proto_data *pd, struct ip_vs_iphdr *iph)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
  {
0b7290212   Alex Gartrell   ipvs: Handle inve...
552
  	__be16 _ports[2], *pptr, dport;
51efbcbbb   Eric W. Biederman   ipvs: Simplify ip...
553
554
  	struct netns_ipvs *ipvs = svc->ipvs;
  	struct net *net = ipvs->net;
9330419d9   Hans Schillstrom   IPVS: netns, use ...
555

d4383f04d   Jesper Dangaard Brouer   ipvs: API change ...
556
  	pptr = frag_safe_skb_hp(skb, iph->len, sizeof(_ports), _ports, iph);
0b7290212   Alex Gartrell   ipvs: Handle inve...
557
  	if (!pptr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
  		return NF_DROP;
0b7290212   Alex Gartrell   ipvs: Handle inve...
559
  	dport = likely(!ip_vs_iph_inverse(iph)) ? pptr[1] : pptr[0];
a7a86b861   Simon Horman   IPVS: Minimise ip...
560

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
  	/* if it is fwmark-based service, the cache_bypass sysctl is up
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
562
  	   and the destination is a non-local unicast, then create
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
  	   a cache_bypass connection entry */
570329487   Eric W. Biederman   ipvs: Wrap sysctl...
564
  	if (sysctl_cache_bypass(ipvs) && svc->fwmark &&
0b7290212   Alex Gartrell   ipvs: Handle inve...
565
566
  	    !(iph->hdr_flags & (IP_VS_HDR_INVERSE | IP_VS_HDR_ICMP)) &&
  	    ip_vs_addr_is_unicast(net, svc->af, &iph->daddr)) {
ad542ced2   Krzysztof Wilczynski   ipvs: Remove unus...
567
  		int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
  		struct ip_vs_conn *cp;
3575792e0   Julian Anastasov   ipvs: extend conn...
569
  		unsigned int flags = (svc->flags & IP_VS_SVC_F_ONEPACKET &&
d4383f04d   Jesper Dangaard Brouer   ipvs: API change ...
570
  				      iph->protocol == IPPROTO_UDP) ?
3575792e0   Julian Anastasov   ipvs: extend conn...
571
  				      IP_VS_CONN_F_ONE_PACKET : 0;
dff630dda   Simon Horman   ipvs: supply a va...
572
  		union nf_inet_addr daddr =  { .all = { 0, 0, 0, 0 } };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
  		/* create a new connection entry */
1e3e238e9   Hannes Eder   IPVS: use pr_err ...
575
576
  		IP_VS_DBG(6, "%s(): create a cache_bypass entry
  ", __func__);
f11017ec2   Simon Horman   IPVS: Add struct ...
577
578
  		{
  			struct ip_vs_conn_param p;
3109d2f2d   Eric W. Biederman   ipvs: Store ipvs ...
579
  			ip_vs_conn_fill_param(svc->ipvs, svc->af, iph->protocol,
d4383f04d   Jesper Dangaard Brouer   ipvs: API change ...
580
581
  					      &iph->saddr, pptr[0],
  					      &iph->daddr, pptr[1], &p);
ba38528aa   Alex Gartrell   ipvs: Supply dest...
582
  			cp = ip_vs_conn_new(&p, svc->af, &daddr, 0,
f11017ec2   Simon Horman   IPVS: Add struct ...
583
  					    IP_VS_CONN_F_BYPASS | flags,
0e051e683   Hans Schillstrom   IPVS: Backup, Pre...
584
  					    NULL, skb->mark);
f11017ec2   Simon Horman   IPVS: Add struct ...
585
586
587
  			if (!cp)
  				return NF_DROP;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
589
590
591
592
  
  		/* statistics */
  		ip_vs_in_stats(cp, skb);
  
  		/* set state */
4a516f110   Simon Horman   ipvs: Remove unus...
593
  		ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
  
  		/* transmit the first SYN packet */
d4383f04d   Jesper Dangaard Brouer   ipvs: API change ...
596
  		ret = cp->packet_xmit(skb, cp, pd->pp, iph);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
598
599
600
601
602
603
604
605
606
607
608
609
  		/* do not touch skb anymore */
  
  		atomic_inc(&cp->in_pkts);
  		ip_vs_conn_put(cp);
  		return ret;
  	}
  
  	/*
  	 * When the virtual ftp service is presented, packets destined
  	 * for other services on the VIP may get here (except services
  	 * listed in the ipvs table), pass the packets, because it is
  	 * not ipvs job to decide to drop the packets.
  	 */
0b7290212   Alex Gartrell   ipvs: Handle inve...
610
  	if (svc->port == FTPPORT && dport != FTPPORT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
  		return NF_ACCEPT;
0b7290212   Alex Gartrell   ipvs: Handle inve...
612
613
614
  
  	if (unlikely(ip_vs_iph_icmp(iph)))
  		return NF_DROP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
616
617
618
619
620
621
622
  
  	/*
  	 * Notify the client that the destination is unreachable, and
  	 * release the socket buffer.
  	 * Since it is in IP layer, the TCP socket is not actually
  	 * created, the TCP RST packet cannot be sent, instead that
  	 * ICMP_PORT_UNREACH is sent here no matter it is TCP/UDP. --WZ
  	 */
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
623
  #ifdef CONFIG_IP_VS_IPV6
cb59155f2   Julian Anastasov   ipvs: changes for...
624
  	if (svc->af == AF_INET6) {
570329487   Eric W. Biederman   ipvs: Wrap sysctl...
625
626
  		if (!skb->dev)
  			skb->dev = net->loopback_dev;
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
627
  		icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
cb59155f2   Julian Anastasov   ipvs: changes for...
628
  	} else
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
629
630
  #endif
  		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
632
  	return NF_DROP;
  }
84b3cee39   Simon Horman   IPVS: Add sysctl_...
633
634
635
636
637
638
639
  #ifdef CONFIG_SYSCTL
  
  static int sysctl_snat_reroute(struct sk_buff *skb)
  {
  	struct netns_ipvs *ipvs = net_ipvs(skb_net(skb));
  	return ipvs->sysctl_snat_reroute;
  }
2300f0451   Eric W. Biederman   ipvs: Pass ipvs n...
640
  static int sysctl_nat_icmp_send(struct netns_ipvs *ipvs)
0cfa558e2   Simon Horman   IPVS: Add sysctl_...
641
  {
0cfa558e2   Simon Horman   IPVS: Add sysctl_...
642
643
  	return ipvs->sysctl_nat_icmp_send;
  }
71a8ab6ca   Simon Horman   IPVS: Add sysctl_...
644
645
646
647
  static int sysctl_expire_nodest_conn(struct netns_ipvs *ipvs)
  {
  	return ipvs->sysctl_expire_nodest_conn;
  }
84b3cee39   Simon Horman   IPVS: Add sysctl_...
648
649
650
  #else
  
  static int sysctl_snat_reroute(struct sk_buff *skb) { return 0; }
2300f0451   Eric W. Biederman   ipvs: Pass ipvs n...
651
  static int sysctl_nat_icmp_send(struct netns_ipvs *ipvs) { return 0; }
71a8ab6ca   Simon Horman   IPVS: Add sysctl_...
652
  static int sysctl_expire_nodest_conn(struct netns_ipvs *ipvs) { return 0; }
84b3cee39   Simon Horman   IPVS: Add sysctl_...
653
654
  
  #endif
b1550f221   Al Viro   [NET]: Annotate i...
655
  __sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
  {
d3bc23e7e   Al Viro   [NET]: Annotate c...
657
  	return csum_fold(skb_checksum(skb, offset, skb->len - offset, 0));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
658
  }
1ca5bb545   Julian Anastasov   ipvs: create ip_v...
659
660
661
662
663
664
665
666
  static inline enum ip_defrag_users ip_vs_defrag_user(unsigned int hooknum)
  {
  	if (NF_INET_LOCAL_IN == hooknum)
  		return IP_DEFRAG_VS_IN;
  	if (NF_INET_FORWARD == hooknum)
  		return IP_DEFRAG_VS_FWD;
  	return IP_DEFRAG_VS_OUT;
  }
776c729e8   Herbert Xu   [IPV4]: Change ip...
667
  static inline int ip_vs_gather_frags(struct sk_buff *skb, u_int32_t user)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
  {
ac69269a4   Julian Anastasov   ipvs: do not disa...
669
  	int err;
776c729e8   Herbert Xu   [IPV4]: Change ip...
670

ac69269a4   Julian Anastasov   ipvs: do not disa...
671
672
673
  	local_bh_disable();
  	err = ip_defrag(skb, user);
  	local_bh_enable();
776c729e8   Herbert Xu   [IPV4]: Change ip...
674
  	if (!err)
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
675
  		ip_send_check(ip_hdr(skb));
776c729e8   Herbert Xu   [IPV4]: Change ip...
676
677
  
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
  }
579eb62ac   Julian Anastasov   ipvs: rerouting t...
679
680
  static int ip_vs_route_me_harder(int af, struct sk_buff *skb,
  				 unsigned int hooknum)
ba4fd7e96   Simon Horman   IPVS: Add ip_vs_r...
681
  {
579eb62ac   Julian Anastasov   ipvs: rerouting t...
682
683
684
685
686
  	if (!sysctl_snat_reroute(skb))
  		return 0;
  	/* Reroute replies only to remote clients (FORWARD and LOCAL_OUT) */
  	if (NF_INET_LOCAL_IN == hooknum)
  		return 0;
ba4fd7e96   Simon Horman   IPVS: Add ip_vs_r...
687
688
  #ifdef CONFIG_IP_VS_IPV6
  	if (af == AF_INET6) {
579eb62ac   Julian Anastasov   ipvs: rerouting t...
689
690
691
692
  		struct dst_entry *dst = skb_dst(skb);
  
  		if (dst->dev && !(dst->dev->flags & IFF_LOOPBACK) &&
  		    ip6_route_me_harder(skb) != 0)
ba4fd7e96   Simon Horman   IPVS: Add ip_vs_r...
693
694
695
  			return 1;
  	} else
  #endif
579eb62ac   Julian Anastasov   ipvs: rerouting t...
696
  		if (!(skb_rtable(skb)->rt_flags & RTCF_LOCAL) &&
ba4fd7e96   Simon Horman   IPVS: Add ip_vs_r...
697
698
699
700
701
  		    ip_route_me_harder(skb, RTN_LOCAL) != 0)
  			return 1;
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
704
705
706
707
708
  /*
   * Packet has been made sufficiently writable in caller
   * - inout: 1=in->out, 0=out->in
   */
  void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
  		    struct ip_vs_conn *cp, int inout)
  {
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
709
  	struct iphdr *iph	 = ip_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
  	unsigned int icmp_offset = iph->ihl*4;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
711
712
  	struct icmphdr *icmph	 = (struct icmphdr *)(skb_network_header(skb) +
  						      icmp_offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
714
715
  	struct iphdr *ciph	 = (struct iphdr *)(icmph + 1);
  
  	if (inout) {
e7ade46a5   Julius Volz   IPVS: Change IPVS...
716
  		iph->saddr = cp->vaddr.ip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
  		ip_send_check(iph);
e7ade46a5   Julius Volz   IPVS: Change IPVS...
718
  		ciph->daddr = cp->vaddr.ip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
720
  		ip_send_check(ciph);
  	} else {
e7ade46a5   Julius Volz   IPVS: Change IPVS...
721
  		iph->daddr = cp->daddr.ip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
  		ip_send_check(iph);
e7ade46a5   Julius Volz   IPVS: Change IPVS...
723
  		ciph->saddr = cp->daddr.ip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724
725
  		ip_send_check(ciph);
  	}
2906f66a5   Venkata Mohan Reddy   ipvs: SCTP Traspo...
726
727
728
  	/* the TCP/UDP/SCTP port */
  	if (IPPROTO_TCP == ciph->protocol || IPPROTO_UDP == ciph->protocol ||
  	    IPPROTO_SCTP == ciph->protocol) {
014d730d5   Al Viro   [IPVS]: ipvs anno...
729
  		__be16 *ports = (void *)ciph + ciph->ihl*4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
731
732
733
734
735
736
737
738
739
740
741
742
  
  		if (inout)
  			ports[1] = cp->vport;
  		else
  			ports[0] = cp->dport;
  	}
  
  	/* And finally the ICMP checksum */
  	icmph->checksum = 0;
  	icmph->checksum = ip_vs_checksum_complete(skb, icmp_offset);
  	skb->ip_summed = CHECKSUM_UNNECESSARY;
  
  	if (inout)
0d79641a9   Julian Anastasov   ipvs: provide add...
743
  		IP_VS_DBG_PKT(11, AF_INET, pp, skb, (void *)ciph - (void *)iph,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
745
  			"Forwarding altered outgoing ICMP");
  	else
0d79641a9   Julian Anastasov   ipvs: provide add...
746
  		IP_VS_DBG_PKT(11, AF_INET, pp, skb, (void *)ciph - (void *)iph,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
  			"Forwarding altered incoming ICMP");
  }
b3cdd2a73   Julius Volz   IPVS: Add and bin...
749
750
751
752
753
  #ifdef CONFIG_IP_VS_IPV6
  void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
  		    struct ip_vs_conn *cp, int inout)
  {
  	struct ipv6hdr *iph	 = ipv6_hdr(skb);
63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
754
755
756
757
758
759
760
761
762
763
764
765
766
  	unsigned int icmp_offset = 0;
  	unsigned int offs	 = 0; /* header offset*/
  	int protocol;
  	struct icmp6hdr *icmph;
  	struct ipv6hdr *ciph;
  	unsigned short fragoffs;
  
  	ipv6_find_hdr(skb, &icmp_offset, IPPROTO_ICMPV6, &fragoffs, NULL);
  	icmph = (struct icmp6hdr *)(skb_network_header(skb) + icmp_offset);
  	offs = icmp_offset + sizeof(struct icmp6hdr);
  	ciph = (struct ipv6hdr *)(skb_network_header(skb) + offs);
  
  	protocol = ipv6_find_hdr(skb, &offs, -1, &fragoffs, NULL);
b3cdd2a73   Julius Volz   IPVS: Add and bin...
767
768
769
770
771
772
773
774
  
  	if (inout) {
  		iph->saddr = cp->vaddr.in6;
  		ciph->daddr = cp->vaddr.in6;
  	} else {
  		iph->daddr = cp->daddr.in6;
  		ciph->saddr = cp->daddr.in6;
  	}
2906f66a5   Venkata Mohan Reddy   ipvs: SCTP Traspo...
775
  	/* the TCP/UDP/SCTP port */
63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
776
777
778
  	if (!fragoffs && (IPPROTO_TCP == protocol || IPPROTO_UDP == protocol ||
  			  IPPROTO_SCTP == protocol)) {
  		__be16 *ports = (void *)(skb_network_header(skb) + offs);
b3cdd2a73   Julius Volz   IPVS: Add and bin...
779

63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
780
781
782
783
  		IP_VS_DBG(11, "%s() changed port %d to %d
  ", __func__,
  			      ntohs(inout ? ports[1] : ports[0]),
  			      ntohs(inout ? cp->vport : cp->dport));
b3cdd2a73   Julius Volz   IPVS: Add and bin...
784
785
786
787
788
789
790
  		if (inout)
  			ports[1] = cp->vport;
  		else
  			ports[0] = cp->dport;
  	}
  
  	/* And finally the ICMP checksum */
8870f8427   Simon Horman   IPVS: ICMPv6 chec...
791
792
793
794
795
796
  	icmph->icmp6_cksum = ~csum_ipv6_magic(&iph->saddr, &iph->daddr,
  					      skb->len - icmp_offset,
  					      IPPROTO_ICMPV6, 0);
  	skb->csum_start = skb_network_header(skb) - skb->head + icmp_offset;
  	skb->csum_offset = offsetof(struct icmp6hdr, icmp6_cksum);
  	skb->ip_summed = CHECKSUM_PARTIAL;
b3cdd2a73   Julius Volz   IPVS: Add and bin...
797
798
  
  	if (inout)
0d79641a9   Julian Anastasov   ipvs: provide add...
799
800
801
  		IP_VS_DBG_PKT(11, AF_INET6, pp, skb,
  			      (void *)ciph - (void *)iph,
  			      "Forwarding altered outgoing ICMPv6");
b3cdd2a73   Julius Volz   IPVS: Add and bin...
802
  	else
0d79641a9   Julian Anastasov   ipvs: provide add...
803
804
805
  		IP_VS_DBG_PKT(11, AF_INET6, pp, skb,
  			      (void *)ciph - (void *)iph,
  			      "Forwarding altered incoming ICMPv6");
b3cdd2a73   Julius Volz   IPVS: Add and bin...
806
807
  }
  #endif
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
808
  /* Handle relevant response ICMP messages - forward to the right
6cb90db50   Julian Anastasov   ipvs: remove extr...
809
   * destination host.
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
810
   */
f2428ed5e   Simon Horman   ipvs: load balanc...
811
812
813
  static int handle_response_icmp(int af, struct sk_buff *skb,
  				union nf_inet_addr *snet,
  				__u8 protocol, struct ip_vs_conn *cp,
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
814
  				struct ip_vs_protocol *pp,
579eb62ac   Julian Anastasov   ipvs: rerouting t...
815
816
  				unsigned int offset, unsigned int ihl,
  				unsigned int hooknum)
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
817
818
819
820
  {
  	unsigned int verdict = NF_DROP;
  
  	if (IP_VS_FWD_METHOD(cp) != 0) {
1e3e238e9   Hannes Eder   IPVS: use pr_err ...
821
822
823
  		pr_err("shouldn't reach here, because the box is on the "
  		       "half connection in the tun/dr module.
  ");
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
824
825
826
827
828
  	}
  
  	/* Ensure the checksum is correct */
  	if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
  		/* Failed checksum! */
f2428ed5e   Simon Horman   ipvs: load balanc...
829
830
831
  		IP_VS_DBG_BUF(1, "Forward ICMP: failed checksum from %s!
  ",
  			      IP_VS_DBG_ADDR(af, snet));
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
832
833
  		goto out;
  	}
2906f66a5   Venkata Mohan Reddy   ipvs: SCTP Traspo...
834
835
  	if (IPPROTO_TCP == protocol || IPPROTO_UDP == protocol ||
  	    IPPROTO_SCTP == protocol)
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
836
837
838
  		offset += 2 * sizeof(__u16);
  	if (!skb_make_writable(skb, offset))
  		goto out;
f2428ed5e   Simon Horman   ipvs: load balanc...
839
840
841
842
843
844
  #ifdef CONFIG_IP_VS_IPV6
  	if (af == AF_INET6)
  		ip_vs_nat_icmp_v6(skb, pp, cp, 1);
  	else
  #endif
  		ip_vs_nat_icmp(skb, pp, cp, 1);
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
845

579eb62ac   Julian Anastasov   ipvs: rerouting t...
846
  	if (ip_vs_route_me_harder(af, skb, hooknum))
ba4fd7e96   Simon Horman   IPVS: Add ip_vs_r...
847
  		goto out;
f5a41847a   Julian Anastasov   ipvs: move ip_rou...
848

4856c84c1   Malcolm Turnbull   ipvs: load balanc...
849
850
  	/* do the statistics and put it back */
  	ip_vs_out_stats(cp, skb);
cf356d69d   Julian Anastasov   ipvs: switch to n...
851
  	skb->ipvs_property = 1;
f4bc17cdd   Julian Anastasov   ipvs: netfilter c...
852
  	if (!(cp->flags & IP_VS_CONN_F_NFCT))
cf356d69d   Julian Anastasov   ipvs: switch to n...
853
  		ip_vs_notrack(skb);
f4bc17cdd   Julian Anastasov   ipvs: netfilter c...
854
855
  	else
  		ip_vs_update_conntrack(skb, cp, 0);
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
856
857
858
859
860
861
862
  	verdict = NF_ACCEPT;
  
  out:
  	__ip_vs_conn_put(cp);
  
  	return verdict;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
864
  /*
   *	Handle ICMP messages in the inside-to-outside direction (outgoing).
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
865
   *	Find any that might be relevant, check against existing connections.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
   *	Currently handles error types - unreachable, quench, ttl exceeded.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
   */
7b5f689a2   Eric W. Biederman   ipvs: Pass ipvs i...
868
869
  static int ip_vs_out_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb,
  			  int *related, unsigned int hooknum)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
870
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
872
873
  	struct iphdr *iph;
  	struct icmphdr	_icmph, *ic;
  	struct iphdr	_ciph, *cih;	/* The ip header contained within the ICMP */
51ef348b1   Julius Volz   IPVS: Add 'af' ar...
874
  	struct ip_vs_iphdr ciph;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
876
  	struct ip_vs_conn *cp;
  	struct ip_vs_protocol *pp;
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
877
  	unsigned int offset, ihl;
f2428ed5e   Simon Horman   ipvs: load balanc...
878
  	union nf_inet_addr snet;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879
880
881
882
  
  	*related = 1;
  
  	/* reassemble IP fragments */
56f8a75c1   Paul Gortmaker   ip: introduce ip_...
883
  	if (ip_is_fragment(ip_hdr(skb))) {
1ca5bb545   Julian Anastasov   ipvs: create ip_v...
884
  		if (ip_vs_gather_frags(skb, ip_vs_defrag_user(hooknum)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885
  			return NF_STOLEN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886
  	}
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
887
  	iph = ip_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
889
890
891
  	offset = ihl = iph->ihl * 4;
  	ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
  	if (ic == NULL)
  		return NF_DROP;
14d5e834f   Harvey Harrison   net: replace NIPQ...
892
893
  	IP_VS_DBG(12, "Outgoing ICMP (%d,%d) %pI4->%pI4
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
  		  ic->type, ntohs(icmp_id(ic)),
14d5e834f   Harvey Harrison   net: replace NIPQ...
895
  		  &iph->saddr, &iph->daddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
  
  	/*
  	 * Work through seeing if this is for us.
  	 * These checks are supposed to be in an order that means easy
  	 * things are checked first to speed up processing.... however
  	 * this means that some packets will manage to get a long way
  	 * down this stack and then be rejected, but that's life.
  	 */
  	if ((ic->type != ICMP_DEST_UNREACH) &&
  	    (ic->type != ICMP_SOURCE_QUENCH) &&
  	    (ic->type != ICMP_TIME_EXCEEDED)) {
  		*related = 0;
  		return NF_ACCEPT;
  	}
  
  	/* Now find the contained IP header */
  	offset += sizeof(_icmph);
  	cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
  	if (cih == NULL)
  		return NF_ACCEPT; /* The packet looks wrong, ignore */
  
  	pp = ip_vs_proto_get(cih->protocol);
  	if (!pp)
  		return NF_ACCEPT;
  
  	/* Is the embedded protocol header present? */
4412ec494   YOSHIFUJI Hideaki   [NET] IPV4: Use h...
922
  	if (unlikely(cih->frag_off & htons(IP_OFFSET) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
924
  		     pp->dont_defrag))
  		return NF_ACCEPT;
0d79641a9   Julian Anastasov   ipvs: provide add...
925
926
  	IP_VS_DBG_PKT(11, AF_INET, pp, skb, offset,
  		      "Checking outgoing ICMP for");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927

4fd9beef3   Alex Gartrell   ipvs: Add hdr_fla...
928
  	ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, true, &ciph);
b0e010c52   Alex Gartrell   ipvs: replace ip_...
929

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930
  	/* The embedded headers contain source and dest in reverse order */
0cf705c8c   Eric W. Biederman   ipvs: Pass ipvs i...
931
  	cp = pp->conn_out_get(ipvs, AF_INET, skb, &ciph);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
933
  	if (!cp)
  		return NF_ACCEPT;
f2428ed5e   Simon Horman   ipvs: load balanc...
934
935
  	snet.ip = iph->saddr;
  	return handle_response_icmp(AF_INET, skb, &snet, cih->protocol, cp,
579eb62ac   Julian Anastasov   ipvs: rerouting t...
936
  				    pp, ciph.len, ihl, hooknum);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937
  }
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
938
  #ifdef CONFIG_IP_VS_IPV6
7b5f689a2   Eric W. Biederman   ipvs: Pass ipvs i...
939
940
941
  static int ip_vs_out_icmp_v6(struct netns_ipvs *ipvs, struct sk_buff *skb,
  			     int *related,  unsigned int hooknum,
  			     struct ip_vs_iphdr *ipvsh)
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
942
  {
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
943
  	struct icmp6hdr	_icmph, *ic;
63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
944
  	struct ip_vs_iphdr ciph = {.flags = 0, .fragoffs = 0};/*Contained IP */
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
945
946
  	struct ip_vs_conn *cp;
  	struct ip_vs_protocol *pp;
f2428ed5e   Simon Horman   ipvs: load balanc...
947
  	union nf_inet_addr snet;
b0e010c52   Alex Gartrell   ipvs: replace ip_...
948
  	unsigned int offset;
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
949

63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
950
  	*related = 1;
2f74713d1   Jesper Dangaard Brouer   ipvs: Complete IP...
951
  	ic = frag_safe_skb_hp(skb, ipvsh->len, sizeof(_icmph), &_icmph, ipvsh);
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
952
953
  	if (ic == NULL)
  		return NF_DROP;
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
954
955
956
957
958
959
960
  	/*
  	 * Work through seeing if this is for us.
  	 * These checks are supposed to be in an order that means easy
  	 * things are checked first to speed up processing.... however
  	 * this means that some packets will manage to get a long way
  	 * down this stack and then be rejected, but that's life.
  	 */
2fab8917f   Jesper Dangaard Brouer   ipvs: IPv6 extend...
961
  	if (ic->icmp6_type & ICMPV6_INFOMSG_MASK) {
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
962
963
964
  		*related = 0;
  		return NF_ACCEPT;
  	}
2f74713d1   Jesper Dangaard Brouer   ipvs: Complete IP...
965
966
967
  	/* Fragment header that is before ICMP header tells us that:
  	 * it's not an error message since they can't be fragmented.
  	 */
e7165030d   David S. Miller   Merge branch 'mas...
968
  	if (ipvsh->flags & IP6_FH_F_FRAG)
2f74713d1   Jesper Dangaard Brouer   ipvs: Complete IP...
969
  		return NF_DROP;
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
970

63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
971
972
973
974
  	IP_VS_DBG(8, "Outgoing ICMPv6 (%d,%d) %pI6c->%pI6c
  ",
  		  ic->icmp6_type, ntohs(icmpv6_id(ic)),
  		  &ipvsh->saddr, &ipvsh->daddr);
4fd9beef3   Alex Gartrell   ipvs: Add hdr_fla...
975
976
  	if (!ip_vs_fill_iph_skb_icmp(AF_INET6, skb, ipvsh->len + sizeof(_icmph),
  				     true, &ciph))
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
977
  		return NF_ACCEPT; /* The packet looks wrong, ignore */
63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
978
979
  
  	pp = ip_vs_proto_get(ciph.protocol);
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
980
981
  	if (!pp)
  		return NF_ACCEPT;
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
982
  	/* The embedded headers contain source and dest in reverse order */
0cf705c8c   Eric W. Biederman   ipvs: Pass ipvs i...
983
  	cp = pp->conn_out_get(ipvs, AF_INET6, skb, &ciph);
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
984
985
  	if (!cp)
  		return NF_ACCEPT;
63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
986
  	snet.in6 = ciph.saddr.in6;
b0e010c52   Alex Gartrell   ipvs: replace ip_...
987
  	offset = ciph.len;
63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
988
  	return handle_response_icmp(AF_INET6, skb, &snet, ciph.protocol, cp,
b0e010c52   Alex Gartrell   ipvs: replace ip_...
989
  				    pp, offset, sizeof(struct ipv6hdr),
579eb62ac   Julian Anastasov   ipvs: rerouting t...
990
  				    hooknum);
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
991
992
  }
  #endif
2906f66a5   Venkata Mohan Reddy   ipvs: SCTP Traspo...
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
  /*
   * Check if sctp chunc is ABORT chunk
   */
  static inline int is_sctp_abort(const struct sk_buff *skb, int nh_len)
  {
  	sctp_chunkhdr_t *sch, schunk;
  	sch = skb_header_pointer(skb, nh_len + sizeof(sctp_sctphdr_t),
  			sizeof(schunk), &schunk);
  	if (sch == NULL)
  		return 0;
  	if (sch->type == SCTP_CID_ABORT)
  		return 1;
  	return 0;
  }
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1007
  static inline int is_tcp_reset(const struct sk_buff *skb, int nh_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
1009
  {
  	struct tcphdr _tcph, *th;
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1010
  	th = skb_header_pointer(skb, nh_len, sizeof(_tcph), &_tcph);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1011
1012
1013
1014
  	if (th == NULL)
  		return 0;
  	return th->rst;
  }
dc7b3eb90   Grzegorz Lyczba   ipvs: Fix reuse c...
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
  static inline bool is_new_conn(const struct sk_buff *skb,
  			       struct ip_vs_iphdr *iph)
  {
  	switch (iph->protocol) {
  	case IPPROTO_TCP: {
  		struct tcphdr _tcph, *th;
  
  		th = skb_header_pointer(skb, iph->len, sizeof(_tcph), &_tcph);
  		if (th == NULL)
  			return false;
  		return th->syn;
  	}
  	case IPPROTO_SCTP: {
  		sctp_chunkhdr_t *sch, schunk;
  
  		sch = skb_header_pointer(skb, iph->len + sizeof(sctp_sctphdr_t),
  					 sizeof(schunk), &schunk);
  		if (sch == NULL)
  			return false;
  		return sch->type == SCTP_CID_INIT;
  	}
  	default:
  		return false;
  	}
  }
d752c3645   Marcelo Ricardo Leitner   ipvs: allow resch...
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
  static inline bool is_new_conn_expected(const struct ip_vs_conn *cp,
  					int conn_reuse_mode)
  {
  	/* Controlled (FTP DATA or persistence)? */
  	if (cp->control)
  		return false;
  
  	switch (cp->protocol) {
  	case IPPROTO_TCP:
  		return (cp->state == IP_VS_TCP_S_TIME_WAIT) ||
  			((conn_reuse_mode & 2) &&
  			 (cp->state == IP_VS_TCP_S_FIN_WAIT) &&
  			 (cp->flags & IP_VS_CONN_F_NOOUTPUT));
  	case IPPROTO_SCTP:
  		return cp->state == IP_VS_SCTP_S_CLOSED;
  	default:
  		return false;
  	}
  }
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
1059
  /* Handle response packets: rewrite addresses and send away...
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
1060
1061
   */
  static unsigned int
9330419d9   Hans Schillstrom   IPVS: netns, use ...
1062
  handle_response(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
579eb62ac   Julian Anastasov   ipvs: rerouting t...
1063
1064
  		struct ip_vs_conn *cp, struct ip_vs_iphdr *iph,
  		unsigned int hooknum)
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
1065
  {
9330419d9   Hans Schillstrom   IPVS: netns, use ...
1066
  	struct ip_vs_protocol *pp = pd->pp;
b0e010c52   Alex Gartrell   ipvs: replace ip_...
1067
  	IP_VS_DBG_PKT(11, af, pp, skb, iph->off, "Outgoing packet");
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
1068

d4383f04d   Jesper Dangaard Brouer   ipvs: API change ...
1069
  	if (!skb_make_writable(skb, iph->len))
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
1070
1071
1072
  		goto drop;
  
  	/* mangle the packet */
d4383f04d   Jesper Dangaard Brouer   ipvs: API change ...
1073
  	if (pp->snat_handler && !pp->snat_handler(skb, pp, cp, iph))
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
  		goto drop;
  
  #ifdef CONFIG_IP_VS_IPV6
  	if (af == AF_INET6)
  		ipv6_hdr(skb)->saddr = cp->vaddr.in6;
  	else
  #endif
  	{
  		ip_hdr(skb)->saddr = cp->vaddr.ip;
  		ip_send_check(ip_hdr(skb));
  	}
8a8030407   Julian Anastasov   ipvs: make rerout...
1085
1086
1087
1088
1089
1090
1091
1092
  	/*
  	 * nf_iterate does not expect change in the skb->dst->dev.
  	 * It looks like it is not fatal to enable this code for hooks
  	 * where our handlers are at the end of the chain list and
  	 * when all next handlers use skb->dst->dev and not outdev.
  	 * It will definitely route properly the inout NAT traffic
  	 * when multiple paths are used.
  	 */
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
1093
1094
1095
1096
1097
1098
  	/* For policy routing, packets originating from this
  	 * machine itself may be routed differently to packets
  	 * passing through.  We want this packet to be routed as
  	 * if it came from this machine itself.  So re-compute
  	 * the routing information.
  	 */
579eb62ac   Julian Anastasov   ipvs: rerouting t...
1099
  	if (ip_vs_route_me_harder(af, skb, hooknum))
ba4fd7e96   Simon Horman   IPVS: Add ip_vs_r...
1100
  		goto drop;
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
1101

b0e010c52   Alex Gartrell   ipvs: replace ip_...
1102
  	IP_VS_DBG_PKT(10, af, pp, skb, iph->off, "After SNAT");
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
1103
1104
  
  	ip_vs_out_stats(cp, skb);
9330419d9   Hans Schillstrom   IPVS: netns, use ...
1105
  	ip_vs_set_state(cp, IP_VS_DIR_OUTPUT, skb, pd);
cf356d69d   Julian Anastasov   ipvs: switch to n...
1106
  	skb->ipvs_property = 1;
f4bc17cdd   Julian Anastasov   ipvs: netfilter c...
1107
  	if (!(cp->flags & IP_VS_CONN_F_NFCT))
cf356d69d   Julian Anastasov   ipvs: switch to n...
1108
  		ip_vs_notrack(skb);
f4bc17cdd   Julian Anastasov   ipvs: netfilter c...
1109
1110
  	else
  		ip_vs_update_conntrack(skb, cp, 0);
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
1111
  	ip_vs_conn_put(cp);
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
1112
1113
1114
1115
1116
1117
  	LeaveFunction(11);
  	return NF_ACCEPT;
  
  drop:
  	ip_vs_conn_put(cp);
  	kfree_skb(skb);
f4bc17cdd   Julian Anastasov   ipvs: netfilter c...
1118
  	LeaveFunction(11);
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
1119
1120
  	return NF_STOLEN;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121
  /*
4856c84c1   Malcolm Turnbull   ipvs: load balanc...
1122
   *	Check if outgoing packet belongs to the established ip_vs_conn.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1123
1124
   */
  static unsigned int
1b75097dd   Eric W. Biederman   ipvs: Pass ipvs i...
1125
  ip_vs_out(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int af)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126
  {
1b75097dd   Eric W. Biederman   ipvs: Pass ipvs i...
1127
  	struct net *net = ipvs->net;
51ef348b1   Julius Volz   IPVS: Add 'af' ar...
1128
  	struct ip_vs_iphdr iph;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
  	struct ip_vs_protocol *pp;
9330419d9   Hans Schillstrom   IPVS: netns, use ...
1130
  	struct ip_vs_proto_data *pd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1131
  	struct ip_vs_conn *cp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132
1133
  
  	EnterFunction(11);
fc6047676   Julian Anastasov   ipvs: changes for...
1134
  	/* Already marked as IPVS request or reply? */
6869c4d8e   Harald Welte   [NETFILTER]: redu...
1135
  	if (skb->ipvs_property)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1136
  		return NF_ACCEPT;
fc6047676   Julian Anastasov   ipvs: changes for...
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
  	/* Bad... Do not break raw sockets */
  	if (unlikely(skb->sk != NULL && hooknum == NF_INET_LOCAL_OUT &&
  		     af == AF_INET)) {
  		struct sock *sk = skb->sk;
  		struct inet_sock *inet = inet_sk(skb->sk);
  
  		if (inet && sk->sk_family == PF_INET && inet->nodefrag)
  			return NF_ACCEPT;
  	}
  
  	if (unlikely(!skb_dst(skb)))
  		return NF_ACCEPT;
48aed1b02   Eric W. Biederman   ipvs: Pass ipvs n...
1149
  	if (!ipvs->enable)
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1150
  		return NF_ACCEPT;
4fd9beef3   Alex Gartrell   ipvs: Add hdr_fla...
1151
  	ip_vs_fill_iph_skb(af, skb, false, &iph);
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1152
1153
1154
  #ifdef CONFIG_IP_VS_IPV6
  	if (af == AF_INET6) {
  		if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
1ca5bb545   Julian Anastasov   ipvs: create ip_v...
1155
  			int related;
7b5f689a2   Eric W. Biederman   ipvs: Pass ipvs i...
1156
  			int verdict = ip_vs_out_icmp_v6(ipvs, skb, &related,
d4383f04d   Jesper Dangaard Brouer   ipvs: API change ...
1157
  							hooknum, &iph);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158

f5a41847a   Julian Anastasov   ipvs: move ip_rou...
1159
  			if (related)
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1160
  				return verdict;
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1161
1162
1163
1164
  		}
  	} else
  #endif
  		if (unlikely(iph.protocol == IPPROTO_ICMP)) {
1ca5bb545   Julian Anastasov   ipvs: create ip_v...
1165
  			int related;
7b5f689a2   Eric W. Biederman   ipvs: Pass ipvs i...
1166
  			int verdict = ip_vs_out_icmp(ipvs, skb, &related, hooknum);
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1167

f5a41847a   Julian Anastasov   ipvs: move ip_rou...
1168
  			if (related)
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1169
  				return verdict;
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1170
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171

18d6ade63   Eric W. Biederman   ipvs: Pass ipvs n...
1172
  	pd = ip_vs_proto_data_get(ipvs, iph.protocol);
9330419d9   Hans Schillstrom   IPVS: netns, use ...
1173
  	if (unlikely(!pd))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1174
  		return NF_ACCEPT;
9330419d9   Hans Schillstrom   IPVS: netns, use ...
1175
  	pp = pd->pp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1176
1177
  
  	/* reassemble IP fragments */
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1178
  #ifdef CONFIG_IP_VS_IPV6
63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
1179
  	if (af == AF_INET)
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1180
  #endif
56f8a75c1   Paul Gortmaker   ip: introduce ip_...
1181
  		if (unlikely(ip_is_fragment(ip_hdr(skb)) && !pp->dont_defrag)) {
1ca5bb545   Julian Anastasov   ipvs: create ip_v...
1182
1183
  			if (ip_vs_gather_frags(skb,
  					       ip_vs_defrag_user(hooknum)))
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1184
  				return NF_STOLEN;
4fd9beef3   Alex Gartrell   ipvs: Add hdr_fla...
1185
  			ip_vs_fill_iph_skb(AF_INET, skb, false, &iph);
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1186
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
1188
1189
1190
  
  	/*
  	 * Check if the packet belongs to an existing entry
  	 */
0cf705c8c   Eric W. Biederman   ipvs: Pass ipvs i...
1191
  	cp = pp->conn_out_get(ipvs, af, skb, &iph);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192

cb59155f2   Julian Anastasov   ipvs: changes for...
1193
  	if (likely(cp))
579eb62ac   Julian Anastasov   ipvs: rerouting t...
1194
  		return handle_response(af, skb, pd, cp, &iph, hooknum);
2300f0451   Eric W. Biederman   ipvs: Pass ipvs n...
1195
  	if (sysctl_nat_icmp_send(ipvs) &&
cb59155f2   Julian Anastasov   ipvs: changes for...
1196
1197
1198
1199
  	    (pp->protocol == IPPROTO_TCP ||
  	     pp->protocol == IPPROTO_UDP ||
  	     pp->protocol == IPPROTO_SCTP)) {
  		__be16 _ports[2], *pptr;
2f74713d1   Jesper Dangaard Brouer   ipvs: Complete IP...
1200
1201
  		pptr = frag_safe_skb_hp(skb, iph.len,
  					 sizeof(_ports), _ports, &iph);
cb59155f2   Julian Anastasov   ipvs: changes for...
1202
1203
  		if (pptr == NULL)
  			return NF_ACCEPT;	/* Not for me */
48aed1b02   Eric W. Biederman   ipvs: Pass ipvs n...
1204
  		if (ip_vs_has_real_service(ipvs, af, iph.protocol, &iph.saddr,
276472eae   Julian Anastasov   ipvs: remove rs_l...
1205
  					   pptr[0])) {
cb59155f2   Julian Anastasov   ipvs: changes for...
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
  			/*
  			 * Notify the real server: there is no
  			 * existing entry if it is not RST
  			 * packet or not TCP packet.
  			 */
  			if ((iph.protocol != IPPROTO_TCP &&
  			     iph.protocol != IPPROTO_SCTP)
  			     || ((iph.protocol == IPPROTO_TCP
  				  && !is_tcp_reset(skb, iph.len))
  				 || (iph.protocol == IPPROTO_SCTP
  					&& !is_sctp_abort(skb,
  						iph.len)))) {
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1218
  #ifdef CONFIG_IP_VS_IPV6
cb59155f2   Julian Anastasov   ipvs: changes for...
1219
  				if (af == AF_INET6) {
cb59155f2   Julian Anastasov   ipvs: changes for...
1220
1221
1222
1223
1224
1225
1226
  					if (!skb->dev)
  						skb->dev = net->loopback_dev;
  					icmpv6_send(skb,
  						    ICMPV6_DEST_UNREACH,
  						    ICMPV6_PORT_UNREACH,
  						    0);
  				} else
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1227
  #endif
cb59155f2   Julian Anastasov   ipvs: changes for...
1228
1229
1230
1231
  					icmp_send(skb,
  						  ICMP_DEST_UNREACH,
  						  ICMP_PORT_UNREACH, 0);
  				return NF_DROP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1232
1233
  			}
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1234
  	}
b0e010c52   Alex Gartrell   ipvs: replace ip_...
1235
  	IP_VS_DBG_PKT(12, af, pp, skb, iph.off,
cb59155f2   Julian Anastasov   ipvs: changes for...
1236
1237
  		      "ip_vs_out: packet continues traversal as normal");
  	return NF_ACCEPT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1238
  }
fc6047676   Julian Anastasov   ipvs: changes for...
1239
  /*
cb59155f2   Julian Anastasov   ipvs: changes for...
1240
1241
   *	It is hooked at the NF_INET_FORWARD and NF_INET_LOCAL_IN chain,
   *	used only for VS/NAT.
fc6047676   Julian Anastasov   ipvs: changes for...
1242
1243
1244
   *	Check if packet is reply for established ip_vs_conn.
   */
  static unsigned int
06198b34a   Eric W. Biederman   netfilter: Pass p...
1245
  ip_vs_reply4(void *priv, struct sk_buff *skb,
238e54c9c   David S. Miller   netfilter: Make n...
1246
  	     const struct nf_hook_state *state)
fc6047676   Julian Anastasov   ipvs: changes for...
1247
  {
1b75097dd   Eric W. Biederman   ipvs: Pass ipvs i...
1248
  	return ip_vs_out(net_ipvs(state->net), state->hook, skb, AF_INET);
fc6047676   Julian Anastasov   ipvs: changes for...
1249
1250
1251
1252
1253
1254
1255
  }
  
  /*
   *	It is hooked at the NF_INET_LOCAL_OUT chain, used only for VS/NAT.
   *	Check if packet is reply for established ip_vs_conn.
   */
  static unsigned int
06198b34a   Eric W. Biederman   netfilter: Pass p...
1256
  ip_vs_local_reply4(void *priv, struct sk_buff *skb,
238e54c9c   David S. Miller   netfilter: Make n...
1257
  		   const struct nf_hook_state *state)
fc6047676   Julian Anastasov   ipvs: changes for...
1258
  {
1b75097dd   Eric W. Biederman   ipvs: Pass ipvs i...
1259
  	return ip_vs_out(net_ipvs(state->net), state->hook, skb, AF_INET);
fc6047676   Julian Anastasov   ipvs: changes for...
1260
1261
1262
1263
1264
  }
  
  #ifdef CONFIG_IP_VS_IPV6
  
  /*
cb59155f2   Julian Anastasov   ipvs: changes for...
1265
1266
   *	It is hooked at the NF_INET_FORWARD and NF_INET_LOCAL_IN chain,
   *	used only for VS/NAT.
fc6047676   Julian Anastasov   ipvs: changes for...
1267
1268
1269
   *	Check if packet is reply for established ip_vs_conn.
   */
  static unsigned int
06198b34a   Eric W. Biederman   netfilter: Pass p...
1270
  ip_vs_reply6(void *priv, struct sk_buff *skb,
238e54c9c   David S. Miller   netfilter: Make n...
1271
  	     const struct nf_hook_state *state)
fc6047676   Julian Anastasov   ipvs: changes for...
1272
  {
1b75097dd   Eric W. Biederman   ipvs: Pass ipvs i...
1273
  	return ip_vs_out(net_ipvs(state->net), state->hook, skb, AF_INET6);
fc6047676   Julian Anastasov   ipvs: changes for...
1274
1275
1276
1277
1278
1279
1280
  }
  
  /*
   *	It is hooked at the NF_INET_LOCAL_OUT chain, used only for VS/NAT.
   *	Check if packet is reply for established ip_vs_conn.
   */
  static unsigned int
06198b34a   Eric W. Biederman   netfilter: Pass p...
1281
  ip_vs_local_reply6(void *priv, struct sk_buff *skb,
238e54c9c   David S. Miller   netfilter: Make n...
1282
  		   const struct nf_hook_state *state)
fc6047676   Julian Anastasov   ipvs: changes for...
1283
  {
1b75097dd   Eric W. Biederman   ipvs: Pass ipvs i...
1284
  	return ip_vs_out(net_ipvs(state->net), state->hook, skb, AF_INET6);
fc6047676   Julian Anastasov   ipvs: changes for...
1285
1286
1287
  }
  
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1288

3b5ca6176   Alex Gartrell   ipvs: pull out ip...
1289
  static unsigned int
d8f44c335   Eric W. Biederman   ipvs: Pass ipvs i...
1290
1291
  ip_vs_try_to_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
  		      struct ip_vs_proto_data *pd,
3b5ca6176   Alex Gartrell   ipvs: pull out ip...
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
  		      int *verdict, struct ip_vs_conn **cpp,
  		      struct ip_vs_iphdr *iph)
  {
  	struct ip_vs_protocol *pp = pd->pp;
  
  	if (!iph->fragoffs) {
  		/* No (second) fragments need to enter here, as nf_defrag_ipv6
  		 * replayed fragment zero will already have created the cp
  		 */
  
  		/* Schedule and create new connection entry into cpp */
d8f44c335   Eric W. Biederman   ipvs: Pass ipvs i...
1303
  		if (!pp->conn_schedule(ipvs, af, skb, pd, verdict, cpp, iph))
3b5ca6176   Alex Gartrell   ipvs: pull out ip...
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
  			return 0;
  	}
  
  	if (unlikely(!*cpp)) {
  		/* sorry, all this trouble for a no-hit :) */
  		IP_VS_DBG_PKT(12, af, pp, skb, iph->off,
  			      "ip_vs_in: packet continues traversal as normal");
  		if (iph->fragoffs) {
  			/* Fragment that couldn't be mapped to a conn entry
  			 * is missing module nf_defrag_ipv6
  			 */
  			IP_VS_DBG_RL("Unhandled frag, load nf_defrag_ipv6
  ");
  			IP_VS_DBG_PKT(7, af, pp, skb, iph->off,
  				      "unhandled fragment");
  		}
  		*verdict = NF_ACCEPT;
  		return 0;
  	}
  
  	return 1;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1326
1327
1328
1329
1330
1331
  /*
   *	Handle ICMP messages in the outside-to-inside direction (incoming).
   *	Find any that might be relevant, check against existing connections,
   *	forward to the right destination host if relevant.
   *	Currently handles error types - unreachable, quench, ttl exceeded.
   */
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1332
  static int
6f2bcea99   Eric W. Biederman   ipvs: Pass ipvs i...
1333
1334
  ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
  	      unsigned int hooknum)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1335
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1336
1337
1338
  	struct iphdr *iph;
  	struct icmphdr	_icmph, *ic;
  	struct iphdr	_ciph, *cih;	/* The ip header contained within the ICMP */
51ef348b1   Julius Volz   IPVS: Add 'af' ar...
1339
  	struct ip_vs_iphdr ciph;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1340
1341
  	struct ip_vs_conn *cp;
  	struct ip_vs_protocol *pp;
9330419d9   Hans Schillstrom   IPVS: netns, use ...
1342
  	struct ip_vs_proto_data *pd;
f2edb9f77   Julian Anastasov   ipvs: implement p...
1343
  	unsigned int offset, offset2, ihl, verdict;
6044eeffa   Alex Gartrell   ipvs: attempt to ...
1344
  	bool ipip, new_cp = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1345
1346
1347
1348
  
  	*related = 1;
  
  	/* reassemble IP fragments */
56f8a75c1   Paul Gortmaker   ip: introduce ip_...
1349
  	if (ip_is_fragment(ip_hdr(skb))) {
1ca5bb545   Julian Anastasov   ipvs: create ip_v...
1350
  		if (ip_vs_gather_frags(skb, ip_vs_defrag_user(hooknum)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1351
  			return NF_STOLEN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1352
  	}
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1353
  	iph = ip_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1354
1355
1356
1357
  	offset = ihl = iph->ihl * 4;
  	ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
  	if (ic == NULL)
  		return NF_DROP;
14d5e834f   Harvey Harrison   net: replace NIPQ...
1358
1359
  	IP_VS_DBG(12, "Incoming ICMP (%d,%d) %pI4->%pI4
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1360
  		  ic->type, ntohs(icmp_id(ic)),
14d5e834f   Harvey Harrison   net: replace NIPQ...
1361
  		  &iph->saddr, &iph->daddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
  
  	/*
  	 * Work through seeing if this is for us.
  	 * These checks are supposed to be in an order that means easy
  	 * things are checked first to speed up processing.... however
  	 * this means that some packets will manage to get a long way
  	 * down this stack and then be rejected, but that's life.
  	 */
  	if ((ic->type != ICMP_DEST_UNREACH) &&
  	    (ic->type != ICMP_SOURCE_QUENCH) &&
  	    (ic->type != ICMP_TIME_EXCEEDED)) {
  		*related = 0;
  		return NF_ACCEPT;
  	}
  
  	/* Now find the contained IP header */
  	offset += sizeof(_icmph);
  	cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
  	if (cih == NULL)
  		return NF_ACCEPT; /* The packet looks wrong, ignore */
f2edb9f77   Julian Anastasov   ipvs: implement p...
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
  	/* Special case for errors for IPIP packets */
  	ipip = false;
  	if (cih->protocol == IPPROTO_IPIP) {
  		if (unlikely(cih->frag_off & htons(IP_OFFSET)))
  			return NF_ACCEPT;
  		/* Error for our IPIP must arrive at LOCAL_IN */
  		if (!(skb_rtable(skb)->rt_flags & RTCF_LOCAL))
  			return NF_ACCEPT;
  		offset += cih->ihl * 4;
  		cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
  		if (cih == NULL)
  			return NF_ACCEPT; /* The packet looks wrong, ignore */
  		ipip = true;
  	}
18d6ade63   Eric W. Biederman   ipvs: Pass ipvs n...
1396
  	pd = ip_vs_proto_data_get(ipvs, cih->protocol);
9330419d9   Hans Schillstrom   IPVS: netns, use ...
1397
  	if (!pd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1398
  		return NF_ACCEPT;
9330419d9   Hans Schillstrom   IPVS: netns, use ...
1399
  	pp = pd->pp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1400
1401
  
  	/* Is the embedded protocol header present? */
4412ec494   YOSHIFUJI Hideaki   [NET] IPV4: Use h...
1402
  	if (unlikely(cih->frag_off & htons(IP_OFFSET) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1403
1404
  		     pp->dont_defrag))
  		return NF_ACCEPT;
0d79641a9   Julian Anastasov   ipvs: provide add...
1405
1406
  	IP_VS_DBG_PKT(11, AF_INET, pp, skb, offset,
  		      "Checking incoming ICMP for");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1407

f2edb9f77   Julian Anastasov   ipvs: implement p...
1408
  	offset2 = offset;
4fd9beef3   Alex Gartrell   ipvs: Add hdr_fla...
1409
  	ip_vs_fill_iph_skb_icmp(AF_INET, skb, offset, !ipip, &ciph);
63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
1410
  	offset = ciph.len;
b0e010c52   Alex Gartrell   ipvs: replace ip_...
1411

f2edb9f77   Julian Anastasov   ipvs: implement p...
1412
1413
1414
  	/* The embedded headers contain source and dest in reverse order.
  	 * For IPIP this is error for request, not for reply.
  	 */
ab1619764   Eric W. Biederman   ipvs: Pass ipvs i...
1415
  	cp = pp->conn_in_get(ipvs, AF_INET, skb, &ciph);
6044eeffa   Alex Gartrell   ipvs: attempt to ...
1416
1417
1418
  
  	if (!cp) {
  		int v;
a47b43008   Eric W. Biederman   ipvs: Cache ipvs ...
1419
  		if (!sysctl_schedule_icmp(ipvs))
6044eeffa   Alex Gartrell   ipvs: attempt to ...
1420
  			return NF_ACCEPT;
d8f44c335   Eric W. Biederman   ipvs: Pass ipvs i...
1421
  		if (!ip_vs_try_to_schedule(ipvs, AF_INET, skb, pd, &v, &cp, &ciph))
6044eeffa   Alex Gartrell   ipvs: attempt to ...
1422
1423
1424
  			return v;
  		new_cp = true;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1425
1426
1427
1428
  
  	verdict = NF_DROP;
  
  	/* Ensure the checksum is correct */
604763722   Herbert Xu   [NET]: Treat CHEC...
1429
  	if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1430
  		/* Failed checksum! */
14d5e834f   Harvey Harrison   net: replace NIPQ...
1431
1432
1433
  		IP_VS_DBG(1, "Incoming ICMP: failed checksum from %pI4!
  ",
  			  &iph->saddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1434
1435
  		goto out;
  	}
f2edb9f77   Julian Anastasov   ipvs: implement p...
1436
1437
  	if (ipip) {
  		__be32 info = ic->un.gateway;
f44a5f45f   Peter Christensen   ipvs: Fix panic d...
1438
1439
  		__u8 type = ic->type;
  		__u8 code = ic->code;
f2edb9f77   Julian Anastasov   ipvs: implement p...
1440
1441
1442
1443
1444
1445
  
  		/* Update the MTU */
  		if (ic->type == ICMP_DEST_UNREACH &&
  		    ic->code == ICMP_FRAG_NEEDED) {
  			struct ip_vs_dest *dest = cp->dest;
  			u32 mtu = ntohs(ic->un.frag.mtu);
f44a5f45f   Peter Christensen   ipvs: Fix panic d...
1446
  			__be16 frag_off = cih->frag_off;
f2edb9f77   Julian Anastasov   ipvs: implement p...
1447
1448
  
  			/* Strip outer IP and ICMP, go to IPIP header */
f44a5f45f   Peter Christensen   ipvs: Fix panic d...
1449
1450
  			if (pskb_pull(skb, ihl + sizeof(_icmph)) == NULL)
  				goto ignore_ipip;
f2edb9f77   Julian Anastasov   ipvs: implement p...
1451
1452
1453
1454
1455
  			offset2 -= ihl + sizeof(_icmph);
  			skb_reset_network_header(skb);
  			IP_VS_DBG(12, "ICMP for IPIP %pI4->%pI4: mtu=%u
  ",
  				&ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr, mtu);
6f2bcea99   Eric W. Biederman   ipvs: Pass ipvs i...
1456
  			ipv4_update_pmtu(skb, ipvs->net,
f2edb9f77   Julian Anastasov   ipvs: implement p...
1457
  					 mtu, 0, 0, 0, 0);
f2edb9f77   Julian Anastasov   ipvs: implement p...
1458
  			/* Client uses PMTUD? */
f44a5f45f   Peter Christensen   ipvs: Fix panic d...
1459
  			if (!(frag_off & htons(IP_DF)))
f2edb9f77   Julian Anastasov   ipvs: implement p...
1460
1461
1462
  				goto ignore_ipip;
  			/* Prefer the resulting PMTU */
  			if (dest) {
026ace060   Julian Anastasov   ipvs: optimize ds...
1463
1464
1465
1466
1467
1468
1469
  				struct ip_vs_dest_dst *dest_dst;
  
  				rcu_read_lock();
  				dest_dst = rcu_dereference(dest->dest_dst);
  				if (dest_dst)
  					mtu = dst_mtu(dest_dst->dst_cache);
  				rcu_read_unlock();
f2edb9f77   Julian Anastasov   ipvs: implement p...
1470
1471
1472
1473
1474
1475
1476
1477
  			}
  			if (mtu > 68 + sizeof(struct iphdr))
  				mtu -= sizeof(struct iphdr);
  			info = htonl(mtu);
  		}
  		/* Strip outer IP, ICMP and IPIP, go to IP header of
  		 * original request.
  		 */
f44a5f45f   Peter Christensen   ipvs: Fix panic d...
1478
1479
  		if (pskb_pull(skb, offset2) == NULL)
  			goto ignore_ipip;
f2edb9f77   Julian Anastasov   ipvs: implement p...
1480
1481
1482
1483
  		skb_reset_network_header(skb);
  		IP_VS_DBG(12, "Sending ICMP for %pI4->%pI4: t=%u, c=%u, i=%u
  ",
  			&ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr,
f44a5f45f   Peter Christensen   ipvs: Fix panic d...
1484
1485
  			type, code, ntohl(info));
  		icmp_send(skb, type, code, info);
f2edb9f77   Julian Anastasov   ipvs: implement p...
1486
1487
1488
1489
1490
1491
1492
1493
  		/* ICMP can be shorter but anyways, account it */
  		ip_vs_out_stats(cp, skb);
  
  ignore_ipip:
  		consume_skb(skb);
  		verdict = NF_STOLEN;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1494
1495
  	/* do the statistics and put it back */
  	ip_vs_in_stats(cp, skb);
06f3d7f97   Julian Anastasov   ipvs: SCTP ports ...
1496
1497
  	if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol ||
  	    IPPROTO_SCTP == cih->protocol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1498
  		offset += 2 * sizeof(__u16);
d4383f04d   Jesper Dangaard Brouer   ipvs: API change ...
1499
  	verdict = ip_vs_icmp_xmit(skb, cp, pp, offset, hooknum, &ciph);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1500

552ad65aa   Hans Schillstrom   IPVS: labels at p...
1501
  out:
6044eeffa   Alex Gartrell   ipvs: attempt to ...
1502
1503
1504
1505
  	if (likely(!new_cp))
  		__ip_vs_conn_put(cp);
  	else
  		ip_vs_conn_put(cp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1506
1507
1508
  
  	return verdict;
  }
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1509
  #ifdef CONFIG_IP_VS_IPV6
6f2bcea99   Eric W. Biederman   ipvs: Pass ipvs i...
1510
1511
1512
  static int ip_vs_in_icmp_v6(struct netns_ipvs *ipvs, struct sk_buff *skb,
  			    int *related, unsigned int hooknum,
  			    struct ip_vs_iphdr *iph)
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1513
  {
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1514
  	struct icmp6hdr	_icmph, *ic;
63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
1515
  	struct ip_vs_iphdr ciph = {.flags = 0, .fragoffs = 0};/*Contained IP */
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1516
1517
  	struct ip_vs_conn *cp;
  	struct ip_vs_protocol *pp;
9330419d9   Hans Schillstrom   IPVS: netns, use ...
1518
  	struct ip_vs_proto_data *pd;
b0e010c52   Alex Gartrell   ipvs: replace ip_...
1519
  	unsigned int offset, verdict;
6044eeffa   Alex Gartrell   ipvs: attempt to ...
1520
  	bool new_cp = false;
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1521

63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
1522
  	*related = 1;
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1523

2f74713d1   Jesper Dangaard Brouer   ipvs: Complete IP...
1524
  	ic = frag_safe_skb_hp(skb, iph->len, sizeof(_icmph), &_icmph, iph);
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1525
1526
  	if (ic == NULL)
  		return NF_DROP;
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1527
1528
1529
1530
1531
1532
1533
  	/*
  	 * Work through seeing if this is for us.
  	 * These checks are supposed to be in an order that means easy
  	 * things are checked first to speed up processing.... however
  	 * this means that some packets will manage to get a long way
  	 * down this stack and then be rejected, but that's life.
  	 */
2fab8917f   Jesper Dangaard Brouer   ipvs: IPv6 extend...
1534
  	if (ic->icmp6_type & ICMPV6_INFOMSG_MASK) {
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1535
1536
1537
  		*related = 0;
  		return NF_ACCEPT;
  	}
2f74713d1   Jesper Dangaard Brouer   ipvs: Complete IP...
1538
1539
1540
  	/* Fragment header that is before ICMP header tells us that:
  	 * it's not an error message since they can't be fragmented.
  	 */
e7165030d   David S. Miller   Merge branch 'mas...
1541
  	if (iph->flags & IP6_FH_F_FRAG)
2f74713d1   Jesper Dangaard Brouer   ipvs: Complete IP...
1542
  		return NF_DROP;
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1543

63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
1544
1545
1546
1547
  	IP_VS_DBG(8, "Incoming ICMPv6 (%d,%d) %pI6c->%pI6c
  ",
  		  ic->icmp6_type, ntohs(icmpv6_id(ic)),
  		  &iph->saddr, &iph->daddr);
b0e010c52   Alex Gartrell   ipvs: replace ip_...
1548
  	offset = iph->len + sizeof(_icmph);
4fd9beef3   Alex Gartrell   ipvs: Add hdr_fla...
1549
  	if (!ip_vs_fill_iph_skb_icmp(AF_INET6, skb, offset, true, &ciph))
b0e010c52   Alex Gartrell   ipvs: replace ip_...
1550
  		return NF_ACCEPT;
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1551

18d6ade63   Eric W. Biederman   ipvs: Pass ipvs n...
1552
  	pd = ip_vs_proto_data_get(ipvs, ciph.protocol);
9330419d9   Hans Schillstrom   IPVS: netns, use ...
1553
  	if (!pd)
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1554
  		return NF_ACCEPT;
9330419d9   Hans Schillstrom   IPVS: netns, use ...
1555
  	pp = pd->pp;
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1556

63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
1557
1558
  	/* Cannot handle fragmented embedded protocol */
  	if (ciph.fragoffs)
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1559
  		return NF_ACCEPT;
b0e010c52   Alex Gartrell   ipvs: replace ip_...
1560
  	IP_VS_DBG_PKT(11, AF_INET6, pp, skb, offset,
0d79641a9   Julian Anastasov   ipvs: provide add...
1561
  		      "Checking incoming ICMPv6 for");
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1562

2f74713d1   Jesper Dangaard Brouer   ipvs: Complete IP...
1563
1564
1565
  	/* The embedded headers contain source and dest in reverse order
  	 * if not from localhost
  	 */
ab1619764   Eric W. Biederman   ipvs: Pass ipvs i...
1566
  	cp = pp->conn_in_get(ipvs, AF_INET6, skb, &ciph);
2f74713d1   Jesper Dangaard Brouer   ipvs: Complete IP...
1567

6044eeffa   Alex Gartrell   ipvs: attempt to ...
1568
1569
  	if (!cp) {
  		int v;
a47b43008   Eric W. Biederman   ipvs: Cache ipvs ...
1570
  		if (!sysctl_schedule_icmp(ipvs))
6044eeffa   Alex Gartrell   ipvs: attempt to ...
1571
  			return NF_ACCEPT;
d8f44c335   Eric W. Biederman   ipvs: Pass ipvs i...
1572
  		if (!ip_vs_try_to_schedule(ipvs, AF_INET6, skb, pd, &v, &cp, &ciph))
6044eeffa   Alex Gartrell   ipvs: attempt to ...
1573
1574
1575
1576
  			return v;
  
  		new_cp = true;
  	}
2f74713d1   Jesper Dangaard Brouer   ipvs: Complete IP...
1577
1578
1579
  	/* VS/TUN, VS/DR and LOCALNODE just let it go */
  	if ((hooknum == NF_INET_LOCAL_OUT) &&
  	    (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)) {
6044eeffa   Alex Gartrell   ipvs: attempt to ...
1580
1581
  		verdict = NF_ACCEPT;
  		goto out;
2f74713d1   Jesper Dangaard Brouer   ipvs: Complete IP...
1582
  	}
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1583

2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1584
1585
  	/* do the statistics and put it back */
  	ip_vs_in_stats(cp, skb);
63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
1586
1587
  
  	/* Need to mangle contained IPv6 header in ICMPv6 packet */
b0e010c52   Alex Gartrell   ipvs: replace ip_...
1588
  	offset = ciph.len;
63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
1589
1590
  	if (IPPROTO_TCP == ciph.protocol || IPPROTO_UDP == ciph.protocol ||
  	    IPPROTO_SCTP == ciph.protocol)
b0e010c52   Alex Gartrell   ipvs: replace ip_...
1591
  		offset += 2 * sizeof(__u16); /* Also mangle ports */
63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
1592

b0e010c52   Alex Gartrell   ipvs: replace ip_...
1593
  	verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, offset, hooknum, &ciph);
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1594

6044eeffa   Alex Gartrell   ipvs: attempt to ...
1595
1596
1597
1598
1599
  out:
  	if (likely(!new_cp))
  		__ip_vs_conn_put(cp);
  	else
  		ip_vs_conn_put(cp);
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1600
1601
1602
1603
  
  	return verdict;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1604
1605
1606
1607
1608
  /*
   *	Check if it's for virtual services, look it up,
   *	and send it on its way...
   */
  static unsigned int
6e385bb3e   Eric W. Biederman   ipvs: Pass ipvs i...
1609
  ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int af)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1610
  {
51ef348b1   Julius Volz   IPVS: Add 'af' ar...
1611
  	struct ip_vs_iphdr iph;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1612
  	struct ip_vs_protocol *pp;
9330419d9   Hans Schillstrom   IPVS: netns, use ...
1613
  	struct ip_vs_proto_data *pd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1614
  	struct ip_vs_conn *cp;
4a516f110   Simon Horman   ipvs: Remove unus...
1615
  	int ret, pkts;
d752c3645   Marcelo Ricardo Leitner   ipvs: allow resch...
1616
  	int conn_reuse_mode;
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1617

fc6047676   Julian Anastasov   ipvs: changes for...
1618
1619
1620
  	/* Already marked as IPVS request or reply? */
  	if (skb->ipvs_property)
  		return NF_ACCEPT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1621
  	/*
cb59155f2   Julian Anastasov   ipvs: changes for...
1622
1623
1624
  	 *	Big tappo:
  	 *	- remote client: only PACKET_HOST
  	 *	- route: used for struct net when skb->dev is unset
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1625
  	 */
cb59155f2   Julian Anastasov   ipvs: changes for...
1626
1627
1628
  	if (unlikely((skb->pkt_type != PACKET_HOST &&
  		      hooknum != NF_INET_LOCAL_OUT) ||
  		     !skb_dst(skb))) {
4fd9beef3   Alex Gartrell   ipvs: Add hdr_fla...
1629
  		ip_vs_fill_iph_skb(af, skb, false, &iph);
cb59155f2   Julian Anastasov   ipvs: changes for...
1630
1631
1632
1633
1634
  		IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s"
  			      " ignored in hook %u
  ",
  			      skb->pkt_type, iph.protocol,
  			      IP_VS_DBG_ADDR(af, &iph.daddr), hooknum);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1635
1636
  		return NF_ACCEPT;
  	}
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1637
  	/* ipvs enabled in this netns ? */
0c12582fb   Julian Anastasov   ipvs: add backup_...
1638
  	if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable))
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1639
  		return NF_ACCEPT;
4fd9beef3   Alex Gartrell   ipvs: Add hdr_fla...
1640
  	ip_vs_fill_iph_skb(af, skb, false, &iph);
cb59155f2   Julian Anastasov   ipvs: changes for...
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
  
  	/* Bad... Do not break raw sockets */
  	if (unlikely(skb->sk != NULL && hooknum == NF_INET_LOCAL_OUT &&
  		     af == AF_INET)) {
  		struct sock *sk = skb->sk;
  		struct inet_sock *inet = inet_sk(skb->sk);
  
  		if (inet && sk->sk_family == PF_INET && inet->nodefrag)
  			return NF_ACCEPT;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1651

94b265514   Julius Volz   IPVS: Add handlin...
1652
1653
1654
  #ifdef CONFIG_IP_VS_IPV6
  	if (af == AF_INET6) {
  		if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
1ca5bb545   Julian Anastasov   ipvs: create ip_v...
1655
  			int related;
6f2bcea99   Eric W. Biederman   ipvs: Pass ipvs i...
1656
1657
  			int verdict = ip_vs_in_icmp_v6(ipvs, skb, &related,
  						       hooknum, &iph);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1658

94b265514   Julius Volz   IPVS: Add handlin...
1659
1660
  			if (related)
  				return verdict;
94b265514   Julius Volz   IPVS: Add handlin...
1661
1662
1663
1664
  		}
  	} else
  #endif
  		if (unlikely(iph.protocol == IPPROTO_ICMP)) {
1ca5bb545   Julian Anastasov   ipvs: create ip_v...
1665
  			int related;
6f2bcea99   Eric W. Biederman   ipvs: Pass ipvs i...
1666
1667
  			int verdict = ip_vs_in_icmp(ipvs, skb, &related,
  						    hooknum);
94b265514   Julius Volz   IPVS: Add handlin...
1668
1669
1670
  
  			if (related)
  				return verdict;
94b265514   Julius Volz   IPVS: Add handlin...
1671
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1672
1673
  
  	/* Protocol supported? */
18d6ade63   Eric W. Biederman   ipvs: Pass ipvs n...
1674
  	pd = ip_vs_proto_data_get(ipvs, iph.protocol);
4e478098a   Alex Gartrell   ipvs: add sysctl ...
1675
1676
1677
1678
1679
1680
1681
  	if (unlikely(!pd)) {
  		/* The only way we'll see this packet again is if it's
  		 * encapsulated, so mark it with ipvs_property=1 so we
  		 * skip it if we're ignoring tunneled packets
  		 */
  		if (sysctl_ignore_tunneled(ipvs))
  			skb->ipvs_property = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1682
  		return NF_ACCEPT;
4e478098a   Alex Gartrell   ipvs: add sysctl ...
1683
  	}
9330419d9   Hans Schillstrom   IPVS: netns, use ...
1684
  	pp = pd->pp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1685
1686
1687
  	/*
  	 * Check if the packet belongs to an existing connection entry
  	 */
ab1619764   Eric W. Biederman   ipvs: Pass ipvs i...
1688
  	cp = pp->conn_in_get(ipvs, af, skb, &iph);
dc7b3eb90   Grzegorz Lyczba   ipvs: Fix reuse c...
1689

d752c3645   Marcelo Ricardo Leitner   ipvs: allow resch...
1690
1691
1692
1693
1694
1695
1696
1697
  	conn_reuse_mode = sysctl_conn_reuse_mode(ipvs);
  	if (conn_reuse_mode && !iph.fragoffs &&
  	    is_new_conn(skb, &iph) && cp &&
  	    ((unlikely(sysctl_expire_nodest_conn(ipvs)) && cp->dest &&
  	      unlikely(!atomic_read(&cp->dest->weight))) ||
  	     unlikely(is_new_conn_expected(cp, conn_reuse_mode)))) {
  		if (!atomic_read(&cp->n_control))
  			ip_vs_conn_expire_now(cp);
dc7b3eb90   Grzegorz Lyczba   ipvs: Fix reuse c...
1698
1699
1700
  		__ip_vs_conn_put(cp);
  		cp = NULL;
  	}
3b5ca6176   Alex Gartrell   ipvs: pull out ip...
1701
  	if (unlikely(!cp)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1702
  		int v;
d8f44c335   Eric W. Biederman   ipvs: Pass ipvs i...
1703
  		if (!ip_vs_try_to_schedule(ipvs, af, skb, pd, &v, &cp, &iph))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1704
1705
  			return v;
  	}
b0e010c52   Alex Gartrell   ipvs: replace ip_...
1706
  	IP_VS_DBG_PKT(11, af, pp, skb, iph.off, "Incoming packet");
3b5ca6176   Alex Gartrell   ipvs: pull out ip...
1707

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1708
1709
1710
  	/* Check the server status */
  	if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) {
  		/* the destination server is not available */
71a8ab6ca   Simon Horman   IPVS: Add sysctl_...
1711
  		if (sysctl_expire_nodest_conn(ipvs)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1712
1713
  			/* try to expire the connection immediately */
  			ip_vs_conn_expire_now(cp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1714
  		}
dc8103f25   Julian Anastasov   [IPVS]: fix conne...
1715
1716
1717
  		/* don't restart its timer, and silently
  		   drop the packet. */
  		__ip_vs_conn_put(cp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1718
1719
1720
1721
  		return NF_DROP;
  	}
  
  	ip_vs_in_stats(cp, skb);
4a516f110   Simon Horman   ipvs: Remove unus...
1722
  	ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1723
  	if (cp->packet_xmit)
d4383f04d   Jesper Dangaard Brouer   ipvs: API change ...
1724
  		ret = cp->packet_xmit(skb, cp, pp, &iph);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1725
1726
1727
1728
1729
  		/* do not touch skb anymore */
  	else {
  		IP_VS_DBG_RL("warning: packet_xmit is null");
  		ret = NF_ACCEPT;
  	}
efac52762   Rumen G. Bogdanovski   [IPVS]: Synchroni...
1730
1731
1732
1733
1734
  	/* Increase its packet counter and check if it is needed
  	 * to be synchronized
  	 *
  	 * Sync connection if it is about to close to
  	 * encorage the standby servers to update the connections timeout
986a07579   Hans Schillstrom   IPVS: Backup, Cha...
1735
1736
  	 *
  	 * For ONE_PKT let ip_vs_sync_conn() do the filter work.
efac52762   Rumen G. Bogdanovski   [IPVS]: Synchroni...
1737
  	 */
f131315fa   Hans Schillstrom   IPVS: netns aware...
1738

986a07579   Hans Schillstrom   IPVS: Backup, Cha...
1739
  	if (cp->flags & IP_VS_CONN_F_ONE_PACKET)
59e0350ea   Simon Horman   IPVS: Add {sysctl...
1740
  		pkts = sysctl_sync_threshold(ipvs);
986a07579   Hans Schillstrom   IPVS: Backup, Cha...
1741
1742
  	else
  		pkts = atomic_add_return(1, &cp->in_pkts);
749c42b62   Julian Anastasov   ipvs: reduce sync...
1743
  	if (ipvs->sync_state & IP_VS_STATE_MASTER)
b61a8c1a4   Eric W. Biederman   ipvs: Pass ipvs n...
1744
  		ip_vs_sync_conn(ipvs, cp, pkts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1745
1746
1747
1748
  
  	ip_vs_conn_put(cp);
  	return ret;
  }
cb59155f2   Julian Anastasov   ipvs: changes for...
1749
1750
1751
1752
1753
  /*
   *	AF_INET handler in NF_INET_LOCAL_IN chain
   *	Schedule and forward packets from remote clients
   */
  static unsigned int
06198b34a   Eric W. Biederman   netfilter: Pass p...
1754
  ip_vs_remote_request4(void *priv, struct sk_buff *skb,
238e54c9c   David S. Miller   netfilter: Make n...
1755
  		      const struct nf_hook_state *state)
cb59155f2   Julian Anastasov   ipvs: changes for...
1756
  {
6e385bb3e   Eric W. Biederman   ipvs: Pass ipvs i...
1757
  	return ip_vs_in(net_ipvs(state->net), state->hook, skb, AF_INET);
cb59155f2   Julian Anastasov   ipvs: changes for...
1758
1759
1760
1761
1762
1763
1764
  }
  
  /*
   *	AF_INET handler in NF_INET_LOCAL_OUT chain
   *	Schedule and forward packets from local clients
   */
  static unsigned int
06198b34a   Eric W. Biederman   netfilter: Pass p...
1765
  ip_vs_local_request4(void *priv, struct sk_buff *skb,
238e54c9c   David S. Miller   netfilter: Make n...
1766
  		     const struct nf_hook_state *state)
cb59155f2   Julian Anastasov   ipvs: changes for...
1767
  {
6e385bb3e   Eric W. Biederman   ipvs: Pass ipvs i...
1768
  	return ip_vs_in(net_ipvs(state->net), state->hook, skb, AF_INET);
cb59155f2   Julian Anastasov   ipvs: changes for...
1769
1770
1771
1772
1773
1774
1775
1776
1777
  }
  
  #ifdef CONFIG_IP_VS_IPV6
  
  /*
   *	AF_INET6 handler in NF_INET_LOCAL_IN chain
   *	Schedule and forward packets from remote clients
   */
  static unsigned int
06198b34a   Eric W. Biederman   netfilter: Pass p...
1778
  ip_vs_remote_request6(void *priv, struct sk_buff *skb,
238e54c9c   David S. Miller   netfilter: Make n...
1779
  		      const struct nf_hook_state *state)
cb59155f2   Julian Anastasov   ipvs: changes for...
1780
  {
6e385bb3e   Eric W. Biederman   ipvs: Pass ipvs i...
1781
  	return ip_vs_in(net_ipvs(state->net), state->hook, skb, AF_INET6);
cb59155f2   Julian Anastasov   ipvs: changes for...
1782
1783
1784
1785
1786
1787
1788
  }
  
  /*
   *	AF_INET6 handler in NF_INET_LOCAL_OUT chain
   *	Schedule and forward packets from local clients
   */
  static unsigned int
06198b34a   Eric W. Biederman   netfilter: Pass p...
1789
  ip_vs_local_request6(void *priv, struct sk_buff *skb,
238e54c9c   David S. Miller   netfilter: Make n...
1790
  		     const struct nf_hook_state *state)
cb59155f2   Julian Anastasov   ipvs: changes for...
1791
  {
6e385bb3e   Eric W. Biederman   ipvs: Pass ipvs i...
1792
  	return ip_vs_in(net_ipvs(state->net), state->hook, skb, AF_INET6);
cb59155f2   Julian Anastasov   ipvs: changes for...
1793
1794
1795
  }
  
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1796
1797
  
  /*
6e23ae2a4   Patrick McHardy   [NETFILTER]: Intr...
1798
   *	It is hooked at the NF_INET_FORWARD chain, in order to catch ICMP
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1799
1800
1801
1802
   *      related packets destined for 0.0.0.0/0.
   *      When fwmark-based virtual service is used, such as transparent
   *      cache cluster, TCP packets can be marked and routed to ip_vs_in,
   *      but ICMP destined for 0.0.0.0/0 cannot not be easily marked and
6e23ae2a4   Patrick McHardy   [NETFILTER]: Intr...
1803
   *      sent to ip_vs_in_icmp. So, catch them at the NF_INET_FORWARD chain
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1804
1805
1806
   *      and send them to ip_vs_in_icmp.
   */
  static unsigned int
06198b34a   Eric W. Biederman   netfilter: Pass p...
1807
  ip_vs_forward_icmp(void *priv, struct sk_buff *skb,
238e54c9c   David S. Miller   netfilter: Make n...
1808
  		   const struct nf_hook_state *state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1809
1810
  {
  	int r;
6f2bcea99   Eric W. Biederman   ipvs: Pass ipvs i...
1811
  	struct netns_ipvs *ipvs = net_ipvs(state->net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1812

3db05fea5   Herbert Xu   [NETFILTER]: Repl...
1813
  	if (ip_hdr(skb)->protocol != IPPROTO_ICMP)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1814
  		return NF_ACCEPT;
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1815
  	/* ipvs enabled in this netns ? */
0c12582fb   Julian Anastasov   ipvs: add backup_...
1816
  	if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable))
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1817
  		return NF_ACCEPT;
6f2bcea99   Eric W. Biederman   ipvs: Pass ipvs i...
1818
  	return ip_vs_in_icmp(ipvs, skb, &r, state->hook);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1819
  }
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1820
1821
  #ifdef CONFIG_IP_VS_IPV6
  static unsigned int
06198b34a   Eric W. Biederman   netfilter: Pass p...
1822
  ip_vs_forward_icmp_v6(void *priv, struct sk_buff *skb,
238e54c9c   David S. Miller   netfilter: Make n...
1823
  		      const struct nf_hook_state *state)
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1824
1825
  {
  	int r;
6f2bcea99   Eric W. Biederman   ipvs: Pass ipvs i...
1826
  	struct netns_ipvs *ipvs = net_ipvs(state->net);
63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
1827
  	struct ip_vs_iphdr iphdr;
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1828

4fd9beef3   Alex Gartrell   ipvs: Add hdr_fla...
1829
  	ip_vs_fill_iph_skb(AF_INET6, skb, false, &iphdr);
63dca2c0b   Jesper Dangaard Brouer   ipvs: Fix faulty ...
1830
  	if (iphdr.protocol != IPPROTO_ICMPV6)
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1831
  		return NF_ACCEPT;
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1832
  	/* ipvs enabled in this netns ? */
0c12582fb   Julian Anastasov   ipvs: add backup_...
1833
  	if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable))
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1834
  		return NF_ACCEPT;
6f2bcea99   Eric W. Biederman   ipvs: Pass ipvs i...
1835
  	return ip_vs_in_icmp_v6(ipvs, skb, &r, state->hook, &iphdr);
2a3b791e6   Julius Volz   IPVS: Add/adjust ...
1836
1837
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1838

1999414a4   Patrick McHardy   [NETFILTER]: Mark...
1839
  static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
cb59155f2   Julian Anastasov   ipvs: changes for...
1840
1841
1842
1843
  	/* After packet filtering, change source only for VS/NAT */
  	{
  		.hook		= ip_vs_reply4,
  		.owner		= THIS_MODULE,
4c809d630   Alban Crequy   netfilter: ipvs: ...
1844
  		.pf		= NFPROTO_IPV4,
cb59155f2   Julian Anastasov   ipvs: changes for...
1845
  		.hooknum	= NF_INET_LOCAL_IN,
afb523c54   Julian Anastasov   ipvs: restore sup...
1846
  		.priority	= NF_IP_PRI_NAT_SRC - 2,
cb59155f2   Julian Anastasov   ipvs: changes for...
1847
  	},
41c5b3170   Patrick McHardy   [NETFILTER]: Use ...
1848
1849
1850
1851
  	/* After packet filtering, forward packet through VS/DR, VS/TUN,
  	 * or VS/NAT(change destination), so that filtering rules can be
  	 * applied to IPVS. */
  	{
cb59155f2   Julian Anastasov   ipvs: changes for...
1852
  		.hook		= ip_vs_remote_request4,
41c5b3170   Patrick McHardy   [NETFILTER]: Use ...
1853
  		.owner		= THIS_MODULE,
4c809d630   Alban Crequy   netfilter: ipvs: ...
1854
  		.pf		= NFPROTO_IPV4,
cb59155f2   Julian Anastasov   ipvs: changes for...
1855
  		.hooknum	= NF_INET_LOCAL_IN,
afb523c54   Julian Anastasov   ipvs: restore sup...
1856
  		.priority	= NF_IP_PRI_NAT_SRC - 1,
41c5b3170   Patrick McHardy   [NETFILTER]: Use ...
1857
  	},
fc6047676   Julian Anastasov   ipvs: changes for...
1858
  	/* Before ip_vs_in, change source only for VS/NAT */
41c5b3170   Patrick McHardy   [NETFILTER]: Use ...
1859
  	{
fc6047676   Julian Anastasov   ipvs: changes for...
1860
  		.hook		= ip_vs_local_reply4,
41c5b3170   Patrick McHardy   [NETFILTER]: Use ...
1861
  		.owner		= THIS_MODULE,
4c809d630   Alban Crequy   netfilter: ipvs: ...
1862
  		.pf		= NFPROTO_IPV4,
fc6047676   Julian Anastasov   ipvs: changes for...
1863
  		.hooknum	= NF_INET_LOCAL_OUT,
afb523c54   Julian Anastasov   ipvs: restore sup...
1864
  		.priority	= NF_IP_PRI_NAT_DST + 1,
41c5b3170   Patrick McHardy   [NETFILTER]: Use ...
1865
  	},
cb59155f2   Julian Anastasov   ipvs: changes for...
1866
1867
1868
1869
  	/* After mangle, schedule and forward local requests */
  	{
  		.hook		= ip_vs_local_request4,
  		.owner		= THIS_MODULE,
4c809d630   Alban Crequy   netfilter: ipvs: ...
1870
  		.pf		= NFPROTO_IPV4,
cb59155f2   Julian Anastasov   ipvs: changes for...
1871
  		.hooknum	= NF_INET_LOCAL_OUT,
afb523c54   Julian Anastasov   ipvs: restore sup...
1872
  		.priority	= NF_IP_PRI_NAT_DST + 2,
cb59155f2   Julian Anastasov   ipvs: changes for...
1873
  	},
41c5b3170   Patrick McHardy   [NETFILTER]: Use ...
1874
1875
1876
1877
1878
  	/* After packet filtering (but before ip_vs_out_icmp), catch icmp
  	 * destined for 0.0.0.0/0, which is for incoming IPVS connections */
  	{
  		.hook		= ip_vs_forward_icmp,
  		.owner		= THIS_MODULE,
4c809d630   Alban Crequy   netfilter: ipvs: ...
1879
  		.pf		= NFPROTO_IPV4,
cb59155f2   Julian Anastasov   ipvs: changes for...
1880
1881
  		.hooknum	= NF_INET_FORWARD,
  		.priority	= 99,
41c5b3170   Patrick McHardy   [NETFILTER]: Use ...
1882
  	},
fc6047676   Julian Anastasov   ipvs: changes for...
1883
1884
1885
1886
  	/* After packet filtering, change source only for VS/NAT */
  	{
  		.hook		= ip_vs_reply4,
  		.owner		= THIS_MODULE,
4c809d630   Alban Crequy   netfilter: ipvs: ...
1887
  		.pf		= NFPROTO_IPV4,
fc6047676   Julian Anastasov   ipvs: changes for...
1888
1889
1890
  		.hooknum	= NF_INET_FORWARD,
  		.priority	= 100,
  	},
473b23d37   Julius Volz   IPVS: Activate IP...
1891
  #ifdef CONFIG_IP_VS_IPV6
cb59155f2   Julian Anastasov   ipvs: changes for...
1892
1893
1894
1895
  	/* After packet filtering, change source only for VS/NAT */
  	{
  		.hook		= ip_vs_reply6,
  		.owner		= THIS_MODULE,
4c809d630   Alban Crequy   netfilter: ipvs: ...
1896
  		.pf		= NFPROTO_IPV6,
cb59155f2   Julian Anastasov   ipvs: changes for...
1897
  		.hooknum	= NF_INET_LOCAL_IN,
afb523c54   Julian Anastasov   ipvs: restore sup...
1898
  		.priority	= NF_IP6_PRI_NAT_SRC - 2,
cb59155f2   Julian Anastasov   ipvs: changes for...
1899
  	},
473b23d37   Julius Volz   IPVS: Activate IP...
1900
1901
1902
1903
  	/* After packet filtering, forward packet through VS/DR, VS/TUN,
  	 * or VS/NAT(change destination), so that filtering rules can be
  	 * applied to IPVS. */
  	{
cb59155f2   Julian Anastasov   ipvs: changes for...
1904
  		.hook		= ip_vs_remote_request6,
473b23d37   Julius Volz   IPVS: Activate IP...
1905
  		.owner		= THIS_MODULE,
4c809d630   Alban Crequy   netfilter: ipvs: ...
1906
  		.pf		= NFPROTO_IPV6,
cb59155f2   Julian Anastasov   ipvs: changes for...
1907
  		.hooknum	= NF_INET_LOCAL_IN,
afb523c54   Julian Anastasov   ipvs: restore sup...
1908
  		.priority	= NF_IP6_PRI_NAT_SRC - 1,
473b23d37   Julius Volz   IPVS: Activate IP...
1909
  	},
fc6047676   Julian Anastasov   ipvs: changes for...
1910
  	/* Before ip_vs_in, change source only for VS/NAT */
473b23d37   Julius Volz   IPVS: Activate IP...
1911
  	{
fc6047676   Julian Anastasov   ipvs: changes for...
1912
  		.hook		= ip_vs_local_reply6,
473b23d37   Julius Volz   IPVS: Activate IP...
1913
  		.owner		= THIS_MODULE,
eb90b0c73   Julian Anastasov   ipvs: fix ipv6 ho...
1914
  		.pf		= NFPROTO_IPV6,
fc6047676   Julian Anastasov   ipvs: changes for...
1915
  		.hooknum	= NF_INET_LOCAL_OUT,
afb523c54   Julian Anastasov   ipvs: restore sup...
1916
  		.priority	= NF_IP6_PRI_NAT_DST + 1,
473b23d37   Julius Volz   IPVS: Activate IP...
1917
  	},
cb59155f2   Julian Anastasov   ipvs: changes for...
1918
1919
1920
1921
  	/* After mangle, schedule and forward local requests */
  	{
  		.hook		= ip_vs_local_request6,
  		.owner		= THIS_MODULE,
4c809d630   Alban Crequy   netfilter: ipvs: ...
1922
  		.pf		= NFPROTO_IPV6,
cb59155f2   Julian Anastasov   ipvs: changes for...
1923
  		.hooknum	= NF_INET_LOCAL_OUT,
afb523c54   Julian Anastasov   ipvs: restore sup...
1924
  		.priority	= NF_IP6_PRI_NAT_DST + 2,
cb59155f2   Julian Anastasov   ipvs: changes for...
1925
  	},
473b23d37   Julius Volz   IPVS: Activate IP...
1926
1927
1928
1929
1930
  	/* After packet filtering (but before ip_vs_out_icmp), catch icmp
  	 * destined for 0.0.0.0/0, which is for incoming IPVS connections */
  	{
  		.hook		= ip_vs_forward_icmp_v6,
  		.owner		= THIS_MODULE,
4c809d630   Alban Crequy   netfilter: ipvs: ...
1931
  		.pf		= NFPROTO_IPV6,
cb59155f2   Julian Anastasov   ipvs: changes for...
1932
1933
  		.hooknum	= NF_INET_FORWARD,
  		.priority	= 99,
473b23d37   Julius Volz   IPVS: Activate IP...
1934
  	},
fc6047676   Julian Anastasov   ipvs: changes for...
1935
1936
1937
1938
  	/* After packet filtering, change source only for VS/NAT */
  	{
  		.hook		= ip_vs_reply6,
  		.owner		= THIS_MODULE,
4c809d630   Alban Crequy   netfilter: ipvs: ...
1939
  		.pf		= NFPROTO_IPV6,
fc6047676   Julian Anastasov   ipvs: changes for...
1940
1941
1942
  		.hooknum	= NF_INET_FORWARD,
  		.priority	= 100,
  	},
473b23d37   Julius Volz   IPVS: Activate IP...
1943
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1944
  };
61b1ab458   Hans Schillstrom   IPVS: netns, add ...
1945
1946
1947
1948
1949
1950
  /*
   *	Initialize IP Virtual Server netns mem.
   */
  static int __net_init __ip_vs_init(struct net *net)
  {
  	struct netns_ipvs *ipvs;
61b1ab458   Hans Schillstrom   IPVS: netns, add ...
1951
  	ipvs = net_generic(net, ip_vs_net_id);
0a9ee8134   Joe Perches   netfilter: Remove...
1952
  	if (ipvs == NULL)
61b1ab458   Hans Schillstrom   IPVS: netns, add ...
1953
  		return -ENOMEM;
0a9ee8134   Joe Perches   netfilter: Remove...
1954

7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1955
1956
  	/* Hold the beast until a service is registerd */
  	ipvs->enable = 0;
f6340ee0c   Hans Schillstrom   IPVS: netns, defe...
1957
  	ipvs->net = net;
61b1ab458   Hans Schillstrom   IPVS: netns, add ...
1958
1959
1960
1961
  	/* Counters used for creating unique names */
  	ipvs->gen = atomic_read(&ipvs_netns_cnt);
  	atomic_inc(&ipvs_netns_cnt);
  	net->ipvs = ipvs;
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1962

a4dd0360c   Eric W. Biederman   ipvs: Pass ipvs n...
1963
  	if (ip_vs_estimator_net_init(ipvs) < 0)
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1964
  		goto estimator_fail;
3d9937668   Eric W. Biederman   ipvs: Pass ipvs n...
1965
  	if (ip_vs_control_net_init(ipvs) < 0)
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1966
  		goto control_fail;
503cf15a5   Hans Schillstrom   IPVS: rename of n...
1967
  	if (ip_vs_protocol_net_init(net) < 0)
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1968
  		goto protocol_fail;
b5dd212cc   Eric W. Biederman   ipvs: Pass ipvs n...
1969
  	if (ip_vs_app_net_init(ipvs) < 0)
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1970
  		goto app_fail;
2f3edc6a5   Eric W. Biederman   ipvs: Pass ipvs n...
1971
  	if (ip_vs_conn_net_init(ipvs) < 0)
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1972
  		goto conn_fail;
802cb4370   Eric W. Biederman   ipvs: Pass ipvs n...
1973
  	if (ip_vs_sync_net_init(ipvs) < 0)
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1974
  		goto sync_fail;
a870c8c5c   Simon Horman   IPVS: use z modif...
1975
1976
  	printk(KERN_INFO "IPVS: Creating netns size=%zu id=%d
  ",
61b1ab458   Hans Schillstrom   IPVS: netns, add ...
1977
1978
  			 sizeof(struct netns_ipvs), ipvs->gen);
  	return 0;
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1979
1980
1981
1982
1983
  /*
   * Error handling
   */
  
  sync_fail:
2f3edc6a5   Eric W. Biederman   ipvs: Pass ipvs n...
1984
  	ip_vs_conn_net_cleanup(ipvs);
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1985
  conn_fail:
b5dd212cc   Eric W. Biederman   ipvs: Pass ipvs n...
1986
  	ip_vs_app_net_cleanup(ipvs);
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1987
  app_fail:
503cf15a5   Hans Schillstrom   IPVS: rename of n...
1988
  	ip_vs_protocol_net_cleanup(net);
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1989
  protocol_fail:
3d9937668   Eric W. Biederman   ipvs: Pass ipvs n...
1990
  	ip_vs_control_net_cleanup(ipvs);
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1991
  control_fail:
a4dd0360c   Eric W. Biederman   ipvs: Pass ipvs n...
1992
  	ip_vs_estimator_net_cleanup(ipvs);
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1993
  estimator_fail:
39f618b4f   Julian Anastasov   ipvs: reset ipvs ...
1994
  	net->ipvs = NULL;
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
1995
  	return -ENOMEM;
61b1ab458   Hans Schillstrom   IPVS: netns, add ...
1996
1997
1998
1999
  }
  
  static void __net_exit __ip_vs_cleanup(struct net *net)
  {
56d2169b7   Eric W. Biederman   ipvs: Pass ipvs n...
2000
2001
2002
  	struct netns_ipvs *ipvs = net_ipvs(net);
  
  	ip_vs_service_net_cleanup(ipvs);	/* ip_vs_flush() with locks */
2f3edc6a5   Eric W. Biederman   ipvs: Pass ipvs n...
2003
  	ip_vs_conn_net_cleanup(ipvs);
b5dd212cc   Eric W. Biederman   ipvs: Pass ipvs n...
2004
  	ip_vs_app_net_cleanup(ipvs);
503cf15a5   Hans Schillstrom   IPVS: rename of n...
2005
  	ip_vs_protocol_net_cleanup(net);
3d9937668   Eric W. Biederman   ipvs: Pass ipvs n...
2006
  	ip_vs_control_net_cleanup(ipvs);
a4dd0360c   Eric W. Biederman   ipvs: Pass ipvs n...
2007
  	ip_vs_estimator_net_cleanup(ipvs);
56d2169b7   Eric W. Biederman   ipvs: Pass ipvs n...
2008
2009
  	IP_VS_DBG(2, "ipvs netns %d released
  ", ipvs->gen);
39f618b4f   Julian Anastasov   ipvs: reset ipvs ...
2010
  	net->ipvs = NULL;
61b1ab458   Hans Schillstrom   IPVS: netns, add ...
2011
  }
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
2012
2013
  static void __net_exit __ip_vs_dev_cleanup(struct net *net)
  {
ebea1f7c0   Eric W. Biederman   ipvs: Pass ipvs n...
2014
  	struct netns_ipvs *ipvs = net_ipvs(net);
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
2015
  	EnterFunction(2);
ebea1f7c0   Eric W. Biederman   ipvs: Pass ipvs n...
2016
  	ipvs->enable = 0;	/* Disable packet reception */
8f4e0a186   Hans Schillstrom   IPVS netns exit c...
2017
  	smp_wmb();
ebea1f7c0   Eric W. Biederman   ipvs: Pass ipvs n...
2018
  	ip_vs_sync_net_cleanup(ipvs);
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
2019
2020
  	LeaveFunction(2);
  }
61b1ab458   Hans Schillstrom   IPVS: netns, add ...
2021
2022
2023
2024
2025
2026
  static struct pernet_operations ipvs_core_ops = {
  	.init = __ip_vs_init,
  	.exit = __ip_vs_cleanup,
  	.id   = &ip_vs_net_id,
  	.size = sizeof(struct netns_ipvs),
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2027

7a4f0761f   Hans Schillstrom   IPVS: init and cl...
2028
2029
2030
  static struct pernet_operations ipvs_core_dev_ops = {
  	.exit = __ip_vs_dev_cleanup,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2031
2032
2033
2034
2035
2036
2037
2038
2039
  /*
   *	Initialize IP Virtual Server
   */
  static int __init ip_vs_init(void)
  {
  	int ret;
  
  	ret = ip_vs_control_init();
  	if (ret < 0) {
1e3e238e9   Hannes Eder   IPVS: use pr_err ...
2040
2041
  		pr_err("can't setup control.
  ");
6c8f79499   Hans Schillstrom   IPVS: remove unus...
2042
  		goto exit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2043
2044
2045
  	}
  
  	ip_vs_protocol_init();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2046
2047
  	ret = ip_vs_conn_init();
  	if (ret < 0) {
1e3e238e9   Hannes Eder   IPVS: use pr_err ...
2048
2049
  		pr_err("can't setup connection table.
  ");
6c8f79499   Hans Schillstrom   IPVS: remove unus...
2050
  		goto cleanup_protocol;
61b1ab458   Hans Schillstrom   IPVS: netns, add ...
2051
  	}
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
2052
2053
  	ret = register_pernet_subsys(&ipvs_core_ops);	/* Alloc ip_vs struct */
  	if (ret < 0)
6c8f79499   Hans Schillstrom   IPVS: remove unus...
2054
  		goto cleanup_conn;
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
2055
2056
2057
2058
  
  	ret = register_pernet_device(&ipvs_core_dev_ops);
  	if (ret < 0)
  		goto cleanup_sub;
41c5b3170   Patrick McHardy   [NETFILTER]: Use ...
2059
  	ret = nf_register_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2060
  	if (ret < 0) {
1e3e238e9   Hannes Eder   IPVS: use pr_err ...
2061
2062
  		pr_err("can't register hooks.
  ");
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
2063
  		goto cleanup_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2064
  	}
8537de8a7   Hans Schillstrom   ipvs: kernel oops...
2065
2066
2067
2068
2069
2070
  	ret = ip_vs_register_nl_ioctl();
  	if (ret < 0) {
  		pr_err("can't register netlink/ioctl.
  ");
  		goto cleanup_hooks;
  	}
1e3e238e9   Hannes Eder   IPVS: use pr_err ...
2071
2072
  	pr_info("ipvs loaded.
  ");
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
2073

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2074
  	return ret;
8537de8a7   Hans Schillstrom   ipvs: kernel oops...
2075
2076
  cleanup_hooks:
  	nf_unregister_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
2077
2078
2079
2080
  cleanup_dev:
  	unregister_pernet_device(&ipvs_core_dev_ops);
  cleanup_sub:
  	unregister_pernet_subsys(&ipvs_core_ops);
552ad65aa   Hans Schillstrom   IPVS: labels at p...
2081
  cleanup_conn:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2082
  	ip_vs_conn_cleanup();
552ad65aa   Hans Schillstrom   IPVS: labels at p...
2083
  cleanup_protocol:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2084
2085
  	ip_vs_protocol_cleanup();
  	ip_vs_control_cleanup();
6c8f79499   Hans Schillstrom   IPVS: remove unus...
2086
  exit:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2087
2088
2089
2090
2091
  	return ret;
  }
  
  static void __exit ip_vs_cleanup(void)
  {
8537de8a7   Hans Schillstrom   ipvs: kernel oops...
2092
  	ip_vs_unregister_nl_ioctl();
41c5b3170   Patrick McHardy   [NETFILTER]: Use ...
2093
  	nf_unregister_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
7a4f0761f   Hans Schillstrom   IPVS: init and cl...
2094
2095
  	unregister_pernet_device(&ipvs_core_dev_ops);
  	unregister_pernet_subsys(&ipvs_core_ops);	/* free ip_vs struct */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2096
  	ip_vs_conn_cleanup();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2097
2098
  	ip_vs_protocol_cleanup();
  	ip_vs_control_cleanup();
1e3e238e9   Hannes Eder   IPVS: use pr_err ...
2099
2100
  	pr_info("ipvs unloaded.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2101
2102
2103
2104
2105
  }
  
  module_init(ip_vs_init);
  module_exit(ip_vs_cleanup);
  MODULE_LICENSE("GPL");