IPVS: Handle Scheduling errors.
If ip_vs_conn_fill_param_persist return an error to ip_vs_sched_persist,
this error must propagate as ignored=-1 to ip_vs_schedule().
Errors from ip_vs_conn_new() in ip_vs_sched_persist() and ip_vs_schedule()
should also return *ignored=-1;
This patch just relies on the fact that ignored is 1 before calling
ip_vs_sched_persist().
Sent from Julian:
"The new case when ip_vs_conn_fill_param_persist fails
should set *ignored = -1, so that we can use NF_DROP,
see below. *ignored = -1 should be also used for ip_vs_conn_new
failure in ip_vs_sched_persist() and ip_vs_schedule().
The new negative value should be handled in tcp,udp,sctp"
"To summarize:
- *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.
- *ignored = 0:
scheduler can not find destination, so try bypass or
return ICMP and then NF_DROP (ip_vs_leave).
- *ignored = -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."
More or less all ideas and input to this patch is work from
Julian Anastasov
Signed-off-by: Hans Schillstrom <hans.schillstrom@ericsson.com>
Acked-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Simon Horman <horms@verge.net.au>
diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
index 9d106a0..cd398de 100644
--- a/net/netfilter/ipvs/ip_vs_proto_udp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
@@ -63,12 +63,18 @@
* incoming connection, and create a connection entry.
*/
*cpp = ip_vs_schedule(svc, skb, pp, &ignored);
- if (!*cpp && !ignored) {
- *verdict = ip_vs_leave(svc, skb, pp);
+ if (!*cpp && ignored <= 0) {
+ if (!ignored)
+ *verdict = ip_vs_leave(svc, skb, pp);
+ else {
+ ip_vs_service_put(svc);
+ *verdict = NF_DROP;
+ }
return 0;
}
ip_vs_service_put(svc);
}
+ /* NF_ACCEPT */
return 1;
}