diff options
-rw-r--r-- | include/net/ip_vs.h | 3 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_core.c | 34 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_proto_sctp.c | 6 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_proto_tcp.c | 7 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_proto_udp.c | 6 |
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); | |||
849 | extern struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name); | 849 | extern struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name); |
850 | extern void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler); | 850 | extern void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler); |
851 | extern struct ip_vs_conn * | 851 | extern struct ip_vs_conn * |
852 | ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb); | 852 | ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, |
853 | struct ip_vs_protocol *pp, int *ignored); | ||
853 | extern int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, | 854 | extern 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 | */ |
344 | struct ip_vs_conn * | 344 | struct ip_vs_conn * |
345 | ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb) | 345 | ip_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 | } |