aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 }