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 | } |
