From: Herbert Xu Date: Wed, 14 Nov 2007 05:43:43 +0000 (-0800) Subject: [IPSEC]: Add async resume support on output X-Git-Tag: v2.6.25-rc1~1162^2~1442 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c6581a457e661b7070e484ad723bbf555b17aca2;p=linux-2.6 [IPSEC]: Add async resume support on output This patch adds support for async resumptions on output. To do so, the transform would return -EINPROGRESS and subsequently invoke the function xfrm_output_resume to resume processing. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- diff --git a/include/net/xfrm.h b/include/net/xfrm.h index ab9e747340..99677207a4 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1119,6 +1119,7 @@ extern void xfrm_replay_notify(struct xfrm_state *x, int event); extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); extern int xfrm_init_state(struct xfrm_state *x); extern int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb); +extern int xfrm_output_resume(struct sk_buff *skb, int err); extern int xfrm_output(struct sk_buff *skb); extern int xfrm4_extract_header(struct sk_buff *skb); extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb); diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index bcb3701c5c..048d240c3e 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -18,6 +18,8 @@ #include #include +static int xfrm_output2(struct sk_buff *skb); + static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb) { struct dst_entry *dst = skb->dst; @@ -41,17 +43,13 @@ err: return err; } -static int xfrm_output_one(struct sk_buff *skb) +static int xfrm_output_one(struct sk_buff *skb, int err) { struct dst_entry *dst = skb->dst; struct xfrm_state *x = dst->xfrm; - int err; - if (skb->ip_summed == CHECKSUM_PARTIAL) { - err = skb_checksum_help(skb); - if (err) - goto error_nolock; - } + if (err <= 0) + goto resume; do { err = x->outer_mode->output(x, skb); @@ -75,6 +73,8 @@ static int xfrm_output_one(struct sk_buff *skb) spin_unlock_bh(&x->lock); err = x->type->output(x, skb); + +resume: if (err) goto error_nolock; @@ -97,18 +97,16 @@ error_nolock: goto out_exit; } -static int xfrm_output2(struct sk_buff *skb) +int xfrm_output_resume(struct sk_buff *skb, int err) { - int err; - - while (likely((err = xfrm_output_one(skb)) == 0)) { + while (likely((err = xfrm_output_one(skb, err)) == 0)) { struct xfrm_state *x; nf_reset(skb); err = skb->dst->ops->local_out(skb); if (unlikely(err != 1)) - break; + goto out; x = skb->dst->xfrm; if (!x) @@ -118,18 +116,25 @@ static int xfrm_output2(struct sk_buff *skb) x->inner_mode->afinfo->nf_post_routing, skb, NULL, skb->dst->dev, xfrm_output2); if (unlikely(err != 1)) - break; + goto out; } + if (err == -EINPROGRESS) + err = 0; + +out: return err; } +EXPORT_SYMBOL_GPL(xfrm_output_resume); -int xfrm_output(struct sk_buff *skb) +static int xfrm_output2(struct sk_buff *skb) { - struct sk_buff *segs; + return xfrm_output_resume(skb, 1); +} - if (!skb_is_gso(skb)) - return xfrm_output2(skb); +static int xfrm_output_gso(struct sk_buff *skb) +{ + struct sk_buff *segs; segs = skb_gso_segment(skb, 0); kfree_skb(skb); @@ -157,4 +162,22 @@ int xfrm_output(struct sk_buff *skb) return 0; } + +int xfrm_output(struct sk_buff *skb) +{ + int err; + + if (skb_is_gso(skb)) + return xfrm_output_gso(skb); + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + err = skb_checksum_help(skb); + if (err) { + kfree_skb(skb); + return err; + } + } + + return xfrm_output2(skb); +} EXPORT_SYMBOL_GPL(xfrm_output);