aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulian Anastasov <ja@ssi.bg>2010-10-17 09:24:37 -0400
committerSimon Horman <horms@verge.net.au>2010-10-21 04:50:41 -0400
commit190ecd27cd7294105e3b26ca71663c7d940acbbb (patch)
tree0dfc3569862e260a7c35c7dee14332de4345eeba
parentcf356d69db0afef692cd640917bc70f708c27f14 (diff)
ipvs: do not schedule conns from real servers
This patch is needed to avoid scheduling of packets from local real server when we add ip_vs_in in LOCAL_OUT hook to support local client. Currently, when ip_vs_in can not find existing connection it tries to create new one by calling ip_vs_schedule. The default indication from ip_vs_schedule was if connection was scheduled to real server. If real server is not available we try to use the bypass forwarding method or to send ICMP error. But in some cases we do not want to use the bypass feature. So, add flag 'ignored' to indicate if the scheduler ignores this packet. Make sure we do not create new connections from replies. We can hit this problem for persistent services and local real server when ip_vs_in is added to LOCAL_OUT hook to handle local clients. Also, make sure ip_vs_schedule ignores SYN packets for Active FTP DATA from local real server. The FTP DATA connection should be created on SYN+ACK from client to assign correct connection daddr. Signed-off-by: Julian Anastasov <ja@ssi.bg> Signed-off-by: Simon Horman <horms@verge.net.au>
-rw-r--r--include/net/ip_vs.h3
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c34
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_sctp.c6
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_tcp.c7
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_udp.c6
5 files changed, 47 insertions, 9 deletions
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 0e4618470cee..9d5c1b965304 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -849,7 +849,8 @@ extern int ip_vs_unbind_scheduler(struct ip_vs_service *svc);
849extern struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name); 849extern struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name);
850extern void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler); 850extern void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler);
851extern struct ip_vs_conn * 851extern struct ip_vs_conn *
852ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb); 852ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,
853 struct ip_vs_protocol *pp, int *ignored);
853extern int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, 854extern int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
854 struct ip_vs_protocol *pp); 855 struct ip_vs_protocol *pp);
855 856
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 222453029b9e..0090d6d25e95 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -342,7 +342,8 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
342 * Protocols supported: TCP, UDP 342 * Protocols supported: TCP, UDP
343 */ 343 */
344struct ip_vs_conn * 344struct ip_vs_conn *
345ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb) 345ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,
346 struct ip_vs_protocol *pp, int *ignored)
346{ 347{
347 struct ip_vs_conn *cp = NULL; 348 struct ip_vs_conn *cp = NULL;
348 struct ip_vs_iphdr iph; 349 struct ip_vs_iphdr iph;
@@ -350,16 +351,43 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb)
350 __be16 _ports[2], *pptr; 351 __be16 _ports[2], *pptr;
351 unsigned int flags; 352 unsigned int flags;
352 353
354 *ignored = 1;
353 ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph); 355 ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
354 pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports); 356 pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports);
355 if (pptr == NULL) 357 if (pptr == NULL)
356 return NULL; 358 return NULL;
357 359
358 /* 360 /*
361 * FTPDATA needs this check when using local real server.
362 * Never schedule Active FTPDATA connections from real server.
363 * For LVS-NAT they must be already created. For other methods
364 * with persistence the connection is created on SYN+ACK.
365 */
366 if (pptr[0] == FTPDATA) {
367 IP_VS_DBG_PKT(12, pp, skb, 0, "Not scheduling FTPDATA");
368 return NULL;
369 }
370
371 /*
372 * Do not schedule replies from local real server. It is risky
373 * for fwmark services but mostly for persistent services.
374 */
375 if ((!skb->dev || skb->dev->flags & IFF_LOOPBACK) &&
376 (svc->flags & IP_VS_SVC_F_PERSISTENT || svc->fwmark) &&
377 (cp = pp->conn_in_get(svc->af, skb, pp, &iph, iph.len, 1))) {
378 IP_VS_DBG_PKT(12, pp, skb, 0,
379 "Not scheduling reply for existing connection");
380 __ip_vs_conn_put(cp);
381 return NULL;
382 }
383
384 /*
359 * Persistent service 385 * Persistent service
360 */ 386 */
361 if (svc->flags & IP_VS_SVC_F_PERSISTENT) 387 if (svc->flags & IP_VS_SVC_F_PERSISTENT) {
388 *ignored = 0;
362 return ip_vs_sched_persist(svc, skb, pptr); 389 return ip_vs_sched_persist(svc, skb, pptr);
390 }
363 391
364 /* 392 /*
365 * Non-persistent service 393 * Non-persistent service
@@ -372,6 +400,8 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb)
372 return NULL; 400 return NULL;
373 } 401 }
374 402
403 *ignored = 0;
404
375 dest = svc->scheduler->schedule(svc, skb); 405 dest = svc->scheduler->schedule(svc, skb);
376 if (dest == NULL) { 406 if (dest == NULL) {
377 IP_VS_DBG(1, "Schedule: no dest found.\n"); 407 IP_VS_DBG(1, "Schedule: no dest found.\n");
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
index 4c0855cb006e..9ab5232ce019 100644
--- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
@@ -31,6 +31,8 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
31 if ((sch->type == SCTP_CID_INIT) && 31 if ((sch->type == SCTP_CID_INIT) &&
32 (svc = ip_vs_service_get(af, skb->mark, iph.protocol, 32 (svc = ip_vs_service_get(af, skb->mark, iph.protocol,
33 &iph.daddr, sh->dest))) { 33 &iph.daddr, sh->dest))) {
34 int ignored;
35
34 if (ip_vs_todrop()) { 36 if (ip_vs_todrop()) {
35 /* 37 /*
36 * It seems that we are very loaded. 38 * It seems that we are very loaded.
@@ -44,8 +46,8 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
44 * Let the virtual server select a real server for the 46 * Let the virtual server select a real server for the
45 * incoming connection, and create a connection entry. 47 * incoming connection, and create a connection entry.
46 */ 48 */
47 *cpp = ip_vs_schedule(svc, skb); 49 *cpp = ip_vs_schedule(svc, skb, pp, &ignored);
48 if (!*cpp) { 50 if (!*cpp && !ignored) {
49 *verdict = ip_vs_leave(svc, skb, pp); 51 *verdict = ip_vs_leave(svc, skb, pp);
50 return 0; 52 return 0;
51 } 53 }
diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
index 64dc2954cf78..85d80a66b492 100644
--- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
@@ -43,9 +43,12 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
43 return 0; 43 return 0;
44 } 44 }
45 45
46 /* No !th->ack check to allow scheduling on SYN+ACK for Active FTP */
46 if (th->syn && 47 if (th->syn &&
47 (svc = ip_vs_service_get(af, skb->mark, iph.protocol, &iph.daddr, 48 (svc = ip_vs_service_get(af, skb->mark, iph.protocol, &iph.daddr,
48 th->dest))) { 49 th->dest))) {
50 int ignored;
51
49 if (ip_vs_todrop()) { 52 if (ip_vs_todrop()) {
50 /* 53 /*
51 * It seems that we are very loaded. 54 * It seems that we are very loaded.
@@ -60,8 +63,8 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
60 * Let the virtual server select a real server for the 63 * Let the virtual server select a real server for the
61 * incoming connection, and create a connection entry. 64 * incoming connection, and create a connection entry.
62 */ 65 */
63 *cpp = ip_vs_schedule(svc, skb); 66 *cpp = ip_vs_schedule(svc, skb, pp, &ignored);
64 if (!*cpp) { 67 if (!*cpp && !ignored) {
65 *verdict = ip_vs_leave(svc, skb, pp); 68 *verdict = ip_vs_leave(svc, skb, pp);
66 return 0; 69 return 0;
67 } 70 }
diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
index 9c558c40bfbb..5d21f08155ed 100644
--- a/net/netfilter/ipvs/ip_vs_proto_udp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
@@ -46,6 +46,8 @@ udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
46 svc = ip_vs_service_get(af, skb->mark, iph.protocol, 46 svc = ip_vs_service_get(af, skb->mark, iph.protocol,
47 &iph.daddr, uh->dest); 47 &iph.daddr, uh->dest);
48 if (svc) { 48 if (svc) {
49 int ignored;
50
49 if (ip_vs_todrop()) { 51 if (ip_vs_todrop()) {
50 /* 52 /*
51 * It seems that we are very loaded. 53 * It seems that we are very loaded.
@@ -60,8 +62,8 @@ udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
60 * Let the virtual server select a real server for the 62 * Let the virtual server select a real server for the
61 * incoming connection, and create a connection entry. 63 * incoming connection, and create a connection entry.
62 */ 64 */
63 *cpp = ip_vs_schedule(svc, skb); 65 *cpp = ip_vs_schedule(svc, skb, pp, &ignored);
64 if (!*cpp) { 66 if (!*cpp && !ignored) {
65 *verdict = ip_vs_leave(svc, skb, pp); 67 *verdict = ip_vs_leave(svc, skb, pp);
66 return 0; 68 return 0;
67 } 69 }