Netdev List
 help / color / mirror / Atom feed
* [PATCH 20/24] [IPSEC]: Add async resume support on output
From: Herbert Xu @ 2007-11-07 14:08 UTC (permalink / raw)
  To: David S. Miller, netdev
In-Reply-To: <20071107140701.GA4685@gondor.apana.org.au>

[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 <herbert@gondor.apana.org.au>
---

 include/net/xfrm.h     |    1 
 net/xfrm/xfrm_output.c |   57 ++++++++++++++++++++++++++++++++++---------------
 2 files changed, 41 insertions(+), 17 deletions(-)

diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index e674a78..b6c26da 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 bcb3701..048d240 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -18,6 +18,8 @@
 #include <net/dst.h>
 #include <net/xfrm.h>
 
+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);

^ permalink raw reply related

* [PATCH 11/24] [IPSEC]: Merge common code into xfrm_bundle_create
From: Herbert Xu @ 2007-11-07 14:08 UTC (permalink / raw)
  To: David S. Miller, netdev
In-Reply-To: <20071107140701.GA4685@gondor.apana.org.au>

[IPSEC]: Merge common code into xfrm_bundle_create

Half of the code in xfrm4_bundle_create and xfrm6_bundle_create are common.
This patch extracts that logic and puts it into xfrm_bundle_create.  The
rest of it are then accessed through afinfo.

As a result this fixes the problem with inter-family transforms where we
treat every xfrm dst in the bundle as if it belongs to the top family.

This patch also fixes a long-standing error-path bug where we may free the
xfrm states twice.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---

 include/net/xfrm.h      |   11 +-
 net/ipv4/xfrm4_policy.c |  134 ++++++-----------------------------
 net/ipv6/xfrm6_policy.c |  143 ++++++-------------------------------
 net/xfrm/xfrm_policy.c  |  183 +++++++++++++++++++++++++++++++++++++++++-------
 4 files changed, 215 insertions(+), 256 deletions(-)

diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 9b6af22..4178c2b 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -227,6 +227,7 @@ struct km_event
 	u32	event;
 };
 
+struct net_device;
 struct xfrm_type;
 struct xfrm_dst;
 struct xfrm_policy_afinfo {
@@ -237,13 +238,11 @@ struct xfrm_policy_afinfo {
 					       xfrm_address_t *daddr);
 	int			(*get_saddr)(xfrm_address_t *saddr, xfrm_address_t *daddr);
 	struct dst_entry	*(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy);
-	int			(*bundle_create)(struct xfrm_policy *policy, 
-						 struct xfrm_state **xfrm, 
-						 int nx,
-						 struct flowi *fl, 
-						 struct dst_entry **dst_p);
 	void			(*decode_session)(struct sk_buff *skb,
 						  struct flowi *fl);
+	int			(*get_tos)(struct flowi *fl);
+	int			(*fill_dst)(struct xfrm_dst *xdst,
+					    struct net_device *dev);
 };
 
 extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo);
@@ -1094,7 +1093,6 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
 }
 #endif
 
-extern struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos);
 struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp);
 extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *);
 int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
@@ -1113,7 +1111,6 @@ extern int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info);
 extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
 extern int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *xdst,
 			  struct flowi *fl, int family, int strict);
-extern void xfrm_init_pmtu(struct dst_entry *dst);
 
 #ifdef CONFIG_XFRM_MIGRATE
 extern int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index cebc847..1d75243 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -79,122 +79,39 @@ __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
 	return dst;
 }
 
-/* Allocate chain of dst_entry's, attach known xfrm's, calculate
- * all the metrics... Shortly, bundle a bundle.
- */
-
-static int
-__xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx,
-		      struct flowi *fl, struct dst_entry **dst_p)
+static int xfrm4_get_tos(struct flowi *fl)
 {
-	struct dst_entry *dst, *dst_prev;
-	struct rtable *rt0 = (struct rtable*)(*dst_p);
-	struct rtable *rt = rt0;
-	int tos = fl->fl4_tos;
-	int i;
-	int err;
-	int header_len = 0;
-	int trailer_len = 0;
-
-	dst = dst_prev = NULL;
-	dst_hold(&rt->u.dst);
-
-	for (i = 0; i < nx; i++) {
-		struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops);
-		struct xfrm_dst *xdst;
-
-		if (unlikely(dst1 == NULL)) {
-			err = -ENOBUFS;
-			dst_release(&rt->u.dst);
-			goto error;
-		}
+	return fl->fl4_tos;
+}
 
-		if (!dst)
-			dst = dst1;
-		else {
-			dst_prev->child = dst1;
-			dst1->flags |= DST_NOHASH;
-			dst_clone(dst1);
-		}
+static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev)
+{
+	struct rtable *rt = (struct rtable *)xdst->route;
 
-		xdst = (struct xfrm_dst *)dst1;
-		xdst->route = &rt->u.dst;
-		xdst->genid = xfrm[i]->genid;
+	xdst->u.rt.fl = rt->fl;
 
-		dst1->next = dst_prev;
-		dst_prev = dst1;
+	xdst->u.dst.dev = dev;
+	dev_hold(dev);
 
-		header_len += xfrm[i]->props.header_len;
-		trailer_len += xfrm[i]->props.trailer_len;
+	xdst->u.rt.idev = in_dev_get(dev);
+	if (!xdst->u.rt.idev)
+		return -ENODEV;
 
-		if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
-			dst1 = xfrm_dst_lookup(xfrm[i], tos);
-			err = PTR_ERR(dst1);
-			if (IS_ERR(dst1))
-				goto error;
+	xdst->u.rt.peer = rt->peer;
+	if (rt->peer)
+		atomic_inc(&rt->peer->refcnt);
 
-			rt = (struct rtable *)dst1;
-		} else
-			dst_hold(&rt->u.dst);
-	}
+	/* Sheit... I remember I did this right. Apparently,
+	 * it was magically lost, so this code needs audit */
+	xdst->u.rt.rt_flags = rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST |
+					      RTCF_LOCAL);
+	xdst->u.rt.rt_type = rt->rt_type;
+	xdst->u.rt.rt_src = rt->rt_src;
+	xdst->u.rt.rt_dst = rt->rt_dst;
+	xdst->u.rt.rt_gateway = rt->rt_gateway;
+	xdst->u.rt.rt_spec_dst = rt->rt_spec_dst;
 
-	dst_prev->child = &rt->u.dst;
-	dst->path = &rt->u.dst;
-
-	/* Copy neighbout for reachability confirmation */
-	dst->neighbour = neigh_clone(rt->u.dst.neighbour);
-
-	*dst_p = dst;
-	dst = dst_prev;
-
-	dst_prev = *dst_p;
-	i = 0;
-	err = -ENODEV;
-	for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
-		struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
-		x->u.rt.fl = *fl;
-
-		dst_prev->xfrm = xfrm[i++];
-		dst_prev->dev = rt->u.dst.dev;
-		if (!rt->u.dst.dev)
-			goto error;
-		dev_hold(rt->u.dst.dev);
-
-		x->u.rt.idev = in_dev_get(rt->u.dst.dev);
-		if (!x->u.rt.idev)
-			goto error;
-
-		dst_prev->obsolete	= -1;
-		dst_prev->flags	       |= DST_HOST;
-		dst_prev->lastuse	= jiffies;
-		dst_prev->header_len	= header_len;
-		dst_prev->trailer_len	= trailer_len;
-		memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
-
-		dst_prev->input = dst_discard;
-		dst_prev->output = dst_prev->xfrm->outer_mode->afinfo->output;
-		if (rt0->peer)
-			atomic_inc(&rt0->peer->refcnt);
-		x->u.rt.peer = rt0->peer;
-		/* Sheit... I remember I did this right. Apparently,
-		 * it was magically lost, so this code needs audit */
-		x->u.rt.rt_flags = rt0->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL);
-		x->u.rt.rt_type = rt0->rt_type;
-		x->u.rt.rt_src = rt0->rt_src;
-		x->u.rt.rt_dst = rt0->rt_dst;
-		x->u.rt.rt_gateway = rt0->rt_gateway;
-		x->u.rt.rt_spec_dst = rt0->rt_spec_dst;
-		header_len -= x->u.dst.xfrm->props.header_len;
-		trailer_len -= x->u.dst.xfrm->props.trailer_len;
-	}
-
-	xfrm_init_pmtu(dst);
 	return 0;
-
-error:
-	if (dst)
-		dst_free(dst);
-	return err;
 }
 
 static void
@@ -330,8 +247,9 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
 	.dst_lookup =		xfrm4_dst_lookup,
 	.get_saddr =		xfrm4_get_saddr,
 	.find_bundle = 		__xfrm4_find_bundle,
-	.bundle_create =	__xfrm4_bundle_create,
 	.decode_session =	_decode_session4,
+	.get_tos =		xfrm4_get_tos,
+	.fill_dst =		xfrm4_fill_dst,
 };
 
 static void __init xfrm4_policy_init(void)
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 864258f..50a3841 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -93,126 +93,34 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
 	return dst;
 }
 
-/* Allocate chain of dst_entry's, attach known xfrm's, calculate
- * all the metrics... Shortly, bundle a bundle.
- */
-
-static int
-__xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx,
-		      struct flowi *fl, struct dst_entry **dst_p)
+static int xfrm6_get_tos(struct flowi *fl)
 {
-	struct dst_entry *dst, *dst_prev;
-	struct rt6_info *rt0 = (struct rt6_info*)(*dst_p);
-	struct rt6_info *rt  = rt0;
-	int i;
-	int err;
-	int header_len = 0;
-	int trailer_len = 0;
-
-	dst = dst_prev = NULL;
-	dst_hold(&rt->u.dst);
-
-	for (i = 0; i < nx; i++) {
-		struct dst_entry *dst1 = dst_alloc(&xfrm6_dst_ops);
-		struct xfrm_dst *xdst;
-
-		if (unlikely(dst1 == NULL)) {
-			err = -ENOBUFS;
-			dst_release(&rt->u.dst);
-			goto error;
-		}
-
-		if (!dst)
-			dst = dst1;
-		else {
-			dst_prev->child = dst1;
-			dst1->flags |= DST_NOHASH;
-			dst_clone(dst1);
-		}
-
-		xdst = (struct xfrm_dst *)dst1;
-		xdst->route = &rt->u.dst;
-		xdst->genid = xfrm[i]->genid;
-		if (rt->rt6i_node)
-			xdst->route_cookie = rt->rt6i_node->fn_sernum;
-
-		dst1->next = dst_prev;
-		dst_prev = dst1;
-
-		if (xfrm[i]->type->flags & XFRM_TYPE_NON_FRAGMENT)
-			((struct rt6_info *)dst)->nfheader_len +=
-				xfrm[i]->props.header_len;
-		header_len += xfrm[i]->props.header_len;
-		trailer_len += xfrm[i]->props.trailer_len;
-
-		if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
-			dst1 = xfrm_dst_lookup(xfrm[i], 0);
-			err = PTR_ERR(dst1);
-			if (IS_ERR(dst1))
-				goto error;
-
-			rt = (struct rt6_info *)dst1;
-		} else
-			dst_hold(&rt->u.dst);
-	}
+	return 0;
+}
 
-	dst_prev->child = &rt->u.dst;
-	dst->path = &rt->u.dst;
-
-	/* Copy neighbour for reachability confirmation */
-	dst->neighbour = neigh_clone(rt->u.dst.neighbour);
-
-	if (rt->rt6i_node)
-		((struct xfrm_dst *)dst)->path_cookie = rt->rt6i_node->fn_sernum;
-
-	*dst_p = dst;
-	dst = dst_prev;
-
-	dst_prev = *dst_p;
-	i = 0;
-	err = -ENODEV;
-	for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
-		struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
-
-		dst_prev->xfrm = xfrm[i++];
-		dst_prev->dev = rt->u.dst.dev;
-		if (!rt->u.dst.dev)
-			goto error;
-		dev_hold(rt->u.dst.dev);
-
-		x->u.rt6.rt6i_idev = in6_dev_get(rt->u.dst.dev);
-		if (!x->u.rt6.rt6i_idev)
-			goto error;
-
-		dst_prev->obsolete	= -1;
-		dst_prev->flags	       |= DST_HOST;
-		dst_prev->lastuse	= jiffies;
-		dst_prev->header_len	= header_len;
-		dst_prev->trailer_len	= trailer_len;
-		memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
-
-		dst_prev->input = dst_discard;
-		dst_prev->output = dst_prev->xfrm->outer_mode->afinfo->output;
-		/* Sheit... I remember I did this right. Apparently,
-		 * it was magically lost, so this code needs audit */
-		x->u.rt6.rt6i_flags    = rt0->rt6i_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL);
-		x->u.rt6.rt6i_metric   = rt0->rt6i_metric;
-		x->u.rt6.rt6i_node     = rt0->rt6i_node;
-		x->u.rt6.rt6i_gateway  = rt0->rt6i_gateway;
-		memcpy(&x->u.rt6.rt6i_gateway, &rt0->rt6i_gateway, sizeof(x->u.rt6.rt6i_gateway));
-		x->u.rt6.rt6i_dst      = rt0->rt6i_dst;
-		x->u.rt6.rt6i_src      = rt0->rt6i_src;
-		header_len -= x->u.dst.xfrm->props.header_len;
-		trailer_len -= x->u.dst.xfrm->props.trailer_len;
-	}
+static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev)
+{
+	struct rt6_info *rt = (struct rt6_info*)xdst->route;
+
+	xdst->u.dst.dev = dev;
+	dev_hold(dev);
+
+	xdst->u.rt6.rt6i_idev = in6_dev_get(rt->u.dst.dev);
+	if (!xdst->u.rt6.rt6i_idev)
+		return -ENODEV;
+
+	/* Sheit... I remember I did this right. Apparently,
+	 * it was magically lost, so this code needs audit */
+	xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTCF_BROADCAST |
+						   RTCF_MULTICAST |
+						   RTCF_LOCAL);
+	xdst->u.rt6.rt6i_metric = rt->rt6i_metric;
+	xdst->u.rt6.rt6i_node = rt->rt6i_node;
+	xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway;
+	xdst->u.rt6.rt6i_dst = rt->rt6i_dst;
+	xdst->u.rt6.rt6i_src = rt->rt6i_src;
 
-	xfrm_init_pmtu(dst);
 	return 0;
-
-error:
-	if (dst)
-		dst_free(dst);
-	return err;
 }
 
 static inline void
@@ -355,8 +263,9 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
 	.dst_lookup =		xfrm6_dst_lookup,
 	.get_saddr = 		xfrm6_get_saddr,
 	.find_bundle =		__xfrm6_find_bundle,
-	.bundle_create =	__xfrm6_bundle_create,
 	.decode_session =	_decode_session6,
+	.get_tos =		xfrm6_get_tos,
+	.fill_dst =		xfrm6_fill_dst,
 };
 
 static void __init xfrm6_policy_init(void)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 6168341..5a03612 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -24,6 +24,7 @@
 #include <linux/netfilter.h>
 #include <linux/module.h>
 #include <linux/cache.h>
+#include <net/dst.h>
 #include <net/xfrm.h>
 #include <net/ip.h>
 
@@ -50,6 +51,7 @@ static DEFINE_SPINLOCK(xfrm_policy_gc_lock);
 
 static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family);
 static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo);
+static void xfrm_init_pmtu(struct dst_entry *dst);
 
 static inline int
 __xfrm4_selector_match(struct xfrm_selector *sel, struct flowi *fl)
@@ -85,7 +87,8 @@ int xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl,
 	return 0;
 }
 
-struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos)
+static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos,
+						int family)
 {
 	xfrm_address_t *saddr = &x->props.saddr;
 	xfrm_address_t *daddr = &x->id.daddr;
@@ -97,7 +100,7 @@ struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos)
 	if (x->type->flags & XFRM_TYPE_REMOTE_COADDR)
 		daddr = x->coaddr;
 
-	afinfo = xfrm_policy_get_afinfo(x->props.family);
+	afinfo = xfrm_policy_get_afinfo(family);
 	if (unlikely(afinfo == NULL))
 		return ERR_PTR(-EAFNOSUPPORT);
 
@@ -105,7 +108,6 @@ struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos)
 	xfrm_policy_put_afinfo(afinfo);
 	return dst;
 }
-EXPORT_SYMBOL(xfrm_dst_lookup);
 
 static inline unsigned long make_jiffies(long secs)
 {
@@ -1235,24 +1237,164 @@ xfrm_find_bundle(struct flowi *fl, struct xfrm_policy *policy, unsigned short fa
 	return x;
 }
 
-/* Allocate chain of dst_entry's, attach known xfrm's, calculate
- * all the metrics... Shortly, bundle a bundle.
- */
+static inline int xfrm_get_tos(struct flowi *fl, int family)
+{
+	struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
+	int tos;
 
-static int
-xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx,
-		   struct flowi *fl, struct dst_entry **dst_p,
-		   unsigned short family)
+	if (!afinfo)
+		return -EINVAL;
+
+	tos = afinfo->get_tos(fl);
+
+	xfrm_policy_put_afinfo(afinfo);
+
+	return tos;
+}
+
+static inline struct xfrm_dst *xfrm_alloc_dst(int family)
 {
-	int err;
 	struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
-	if (unlikely(afinfo == NULL))
+	struct xfrm_dst *xdst;
+
+	if (!afinfo)
+		return ERR_PTR(-EINVAL);
+
+	xdst = dst_alloc(afinfo->dst_ops) ?: ERR_PTR(-ENOBUFS);
+
+	xfrm_policy_put_afinfo(afinfo);
+
+	return xdst;
+}
+
+static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev)
+{
+	struct xfrm_policy_afinfo *afinfo =
+		xfrm_policy_get_afinfo(xdst->u.dst.ops->family);
+	int err;
+
+	if (!afinfo)
 		return -EINVAL;
-	err = afinfo->bundle_create(policy, xfrm, nx, fl, dst_p);
+
+	err = afinfo->fill_dst(xdst, dev);
+
 	xfrm_policy_put_afinfo(afinfo);
+
 	return err;
 }
 
+/* Allocate chain of dst_entry's, attach known xfrm's, calculate
+ * all the metrics... Shortly, bundle a bundle.
+ */
+
+static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
+					    struct xfrm_state **xfrm, int nx,
+					    struct flowi *fl,
+					    struct dst_entry *dst)
+{
+	unsigned long now = jiffies;
+	struct net_device *dev;
+	struct dst_entry *dst_prev = NULL;
+	struct dst_entry *dst0 = NULL;
+	int i = 0;
+	int err;
+	int header_len = 0;
+	int trailer_len = 0;
+	int tos;
+	int family = policy->selector.family;
+
+	tos = xfrm_get_tos(fl, family);
+	err = tos;
+	if (tos < 0)
+		goto put_states;
+
+	dst_hold(dst);
+
+	for (; i < nx; i++) {
+		struct xfrm_dst *xdst = xfrm_alloc_dst(family);
+		struct dst_entry *dst1 = &xdst->u.dst;
+
+		err = PTR_ERR(xdst);
+		if (IS_ERR(xdst)) {
+			dst_release(dst);
+			goto put_states;
+		}
+
+		if (!dst_prev)
+			dst0 = dst1;
+		else {
+			dst_prev->child = dst_clone(dst1);
+			dst1->flags |= DST_NOHASH;
+		}
+
+		xdst->route = dst;
+		memcpy(&dst1->metrics, &dst->metrics, sizeof(dst->metrics));
+
+		if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
+			family = xfrm[i]->props.family;
+			dst = xfrm_dst_lookup(xfrm[i], tos, family);
+			err = PTR_ERR(dst);
+			if (IS_ERR(dst))
+				goto put_states;
+		} else
+			dst_hold(dst);
+
+		dst1->xfrm = xfrm[i];
+		xdst->genid = xfrm[i]->genid;
+
+		dst1->obsolete = -1;
+		dst1->flags |= DST_HOST;
+		dst1->lastuse = now;
+
+		dst1->input = dst_discard;
+		dst1->output = xfrm[i]->outer_mode->afinfo->output;
+
+		dst1->next = dst_prev;
+		dst_prev = dst1;
+
+		header_len += xfrm[i]->props.header_len;
+		trailer_len += xfrm[i]->props.trailer_len;
+	}
+
+	dst_prev->child = dst;
+	dst0->path = dst;
+
+	err = -ENODEV;
+	dev = dst->dev;
+	if (!dev)
+		goto free_dst;
+
+	/* Copy neighbout for reachability confirmation */
+	dst0->neighbour = neigh_clone(dst->neighbour);
+
+	xfrm_init_pmtu(dst_prev);
+
+	for (dst_prev = dst0; dst_prev != dst; dst_prev = dst_prev->child) {
+		struct xfrm_dst *xdst = (struct xfrm_dst *)dst_prev;
+
+		err = xfrm_fill_dst(xdst, dev);
+		if (err)
+			goto free_dst;
+
+		dst_prev->header_len = header_len;
+		dst_prev->trailer_len = trailer_len;
+		header_len -= xdst->u.dst.xfrm->props.header_len;
+		trailer_len -= xdst->u.dst.xfrm->props.trailer_len;
+	}
+
+out:
+	return dst0;
+
+put_states:
+	for (; i < nx; i++)
+		xfrm_state_put(xfrm[i]);
+free_dst:
+	if (dst0)
+		dst_free(dst0);
+	dst0 = ERR_PTR(err);
+	goto out;
+}
+
 static int inline
 xfrm_dst_alloc_copy(void **target, void *src, int size)
 {
@@ -1452,15 +1594,10 @@ restart:
 			return 0;
 		}
 
-		dst = dst_orig;
-		err = xfrm_bundle_create(policy, xfrm, nx, fl, &dst, family);
-
-		if (unlikely(err)) {
-			int i;
-			for (i=0; i<nx; i++)
-				xfrm_state_put(xfrm[i]);
+		dst = xfrm_bundle_create(policy, xfrm, nx, fl, dst_orig);
+		err = PTR_ERR(dst);
+		if (IS_ERR(dst))
 			goto error;
-		}
 
 		for (pi = 0; pi < npols; pi++) {
 			read_lock_bh(&pols[pi]->lock);
@@ -1883,7 +2020,7 @@ static int xfrm_flush_bundles(void)
 	return 0;
 }
 
-void xfrm_init_pmtu(struct dst_entry *dst)
+static void xfrm_init_pmtu(struct dst_entry *dst)
 {
 	do {
 		struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
@@ -1904,8 +2041,6 @@ void xfrm_init_pmtu(struct dst_entry *dst)
 	} while ((dst = dst->next));
 }
 
-EXPORT_SYMBOL(xfrm_init_pmtu);
-
 /* Check that the bundle accepts the flow and its components are
  * still valid.
  */

^ permalink raw reply related

* [PATCH 21/24] [IPSEC]: Merge most of the input path
From: Herbert Xu @ 2007-11-07 14:08 UTC (permalink / raw)
  To: David S. Miller, netdev
In-Reply-To: <20071107140701.GA4685@gondor.apana.org.au>

[IPSEC]: Merge most of the input path

As part of the work on asynchrnous cryptographic operations, we need to
be able to resume from the spot where they occur.  As such, it helps if
we isolate them to one spot.

This patch moves most of the remaining family-specific processing into
the common input code.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---

 include/net/xfrm.h     |   22 ++++++++
 net/ipv4/xfrm4_input.c |  126 +++++--------------------------------------------
 net/ipv4/xfrm4_state.c |    1 
 net/ipv6/xfrm6_input.c |  118 +++++----------------------------------------
 net/ipv6/xfrm6_state.c |    1 
 net/xfrm/xfrm_input.c  |  113 +++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 164 insertions(+), 217 deletions(-)

diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index b6c26da..5c457b0 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -274,6 +274,8 @@ struct xfrm_state_afinfo {
 						 struct sk_buff *skb);
 	int			(*extract_output)(struct xfrm_state *x,
 						  struct sk_buff *skb);
+	int			(*transport_finish)(struct sk_buff *skb,
+						    int async);
 };
 
 extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo);
@@ -522,6 +524,22 @@ struct xfrm_mode_skb_cb {
 
 #define XFRM_MODE_SKB_CB(__skb) ((struct xfrm_mode_skb_cb *)&((__skb)->cb[0]))
 
+/*
+ * This structure is used by the input processing to locate the SPI and
+ * related information.
+ */
+struct xfrm_spi_skb_cb {
+	union {
+		struct inet_skb_parm h4;
+		struct inet6_skb_parm h6;
+	} header;
+
+	unsigned int nhoff;
+	unsigned int daddroff;
+};
+
+#define XFRM_SPI_SKB_CB(__skb) ((struct xfrm_spi_skb_cb *)&((__skb)->cb[0]))
+
 /* Audit Information */
 struct xfrm_audit
 {
@@ -1119,12 +1137,15 @@ 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_input(struct sk_buff *skb, int nexthdr, __be32 spi,
+		      int encap_type);
 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);
 extern int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
 			   int encap_type);
+extern int xfrm4_transport_finish(struct sk_buff *skb, int async);
 extern int xfrm4_rcv(struct sk_buff *skb);
 
 static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi)
@@ -1140,6 +1161,7 @@ extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short f
 extern int xfrm6_extract_header(struct sk_buff *skb);
 extern int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb);
 extern int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi);
+extern int xfrm6_transport_finish(struct sk_buff *skb, int async);
 extern int xfrm6_rcv(struct sk_buff *skb);
 extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
 			    xfrm_address_t *saddr, u8 proto);
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index c0323d0..e374903 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -41,124 +41,26 @@ drop:
 int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
 		    int encap_type)
 {
-	int err;
-	__be32 seq;
-	struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
-	struct xfrm_state *x;
-	int xfrm_nr = 0;
-	int decaps = 0;
-	unsigned int nhoff = offsetof(struct iphdr, protocol);
-
-	seq = 0;
-	if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0)
-		goto drop;
-
-	do {
-		const struct iphdr *iph = ip_hdr(skb);
-
-		if (xfrm_nr == XFRM_MAX_DEPTH)
-			goto drop;
-
-		x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi,
-				      nexthdr, AF_INET);
-		if (x == NULL)
-			goto drop;
-
-		spin_lock(&x->lock);
-		if (unlikely(x->km.state != XFRM_STATE_VALID))
-			goto drop_unlock;
-
-		if ((x->encap ? x->encap->encap_type : 0) != encap_type)
-			goto drop_unlock;
-
-		if (x->props.replay_window && xfrm_replay_check(x, seq))
-			goto drop_unlock;
-
-		if (xfrm_state_check_expire(x))
-			goto drop_unlock;
-
-		nexthdr = x->type->input(x, skb);
-		if (nexthdr <= 0)
-			goto drop_unlock;
-
-		skb_network_header(skb)[nhoff] = nexthdr;
-
-		/* only the first xfrm gets the encap type */
-		encap_type = 0;
-
-		if (x->props.replay_window)
-			xfrm_replay_advance(x, seq);
-
-		x->curlft.bytes += skb->len;
-		x->curlft.packets++;
-
-		spin_unlock(&x->lock);
-
-		xfrm_vec[xfrm_nr++] = x;
-
-		if (x->inner_mode->input(x, skb))
-			goto drop;
-
-		if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) {
-			decaps = 1;
-			break;
-		}
-
-		err = xfrm_parse_spi(skb, nexthdr, &spi, &seq);
-		if (err < 0)
-			goto drop;
-	} while (!err);
-
-	/* Allocate new secpath or COW existing one. */
-
-	if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
-		struct sec_path *sp;
-		sp = secpath_dup(skb->sp);
-		if (!sp)
-			goto drop;
-		if (skb->sp)
-			secpath_put(skb->sp);
-		skb->sp = sp;
-	}
-	if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
-		goto drop;
-
-	memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec,
-	       xfrm_nr * sizeof(xfrm_vec[0]));
-	skb->sp->len += xfrm_nr;
-
-	nf_reset(skb);
+	XFRM_SPI_SKB_CB(skb)->nhoff = offsetof(struct iphdr, protocol);
+	XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
+	return xfrm_input(skb, nexthdr, spi, encap_type);
+}
+EXPORT_SYMBOL(xfrm4_rcv_encap);
 
-	if (decaps) {
-		dst_release(skb->dst);
-		skb->dst = NULL;
-		netif_rx(skb);
-		return 0;
-	} else {
+int xfrm4_transport_finish(struct sk_buff *skb, int async)
+{
 #ifdef CONFIG_NETFILTER
-		__skb_push(skb, skb->data - skb_network_header(skb));
-		ip_hdr(skb)->tot_len = htons(skb->len);
-		ip_send_check(ip_hdr(skb));
+	__skb_push(skb, skb->data - skb_network_header(skb));
+	ip_hdr(skb)->tot_len = htons(skb->len);
+	ip_send_check(ip_hdr(skb));
 
-		NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL,
-			xfrm4_rcv_encap_finish);
-		return 0;
+	NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL,
+		xfrm4_rcv_encap_finish);
+	return 0;
 #else
-		return -ip_hdr(skb)->protocol;
+	return -ip_hdr(skb)->protocol;
 #endif
-	}
-
-drop_unlock:
-	spin_unlock(&x->lock);
-	xfrm_state_put(x);
-drop:
-	while (--xfrm_nr >= 0)
-		xfrm_state_put(xfrm_vec[xfrm_nr]);
-
-	kfree_skb(skb);
-	return 0;
 }
-EXPORT_SYMBOL(xfrm4_rcv_encap);
 
 /* If it's a keepalive packet, then just eat it.
  * If it's an encapsulated packet, then pass it to the
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index 80292fb..3b067e8 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -74,6 +74,7 @@ static struct xfrm_state_afinfo xfrm4_state_afinfo = {
 	.output			= xfrm4_output,
 	.extract_input		= xfrm4_extract_input,
 	.extract_output		= xfrm4_extract_output,
+	.transport_finish	= xfrm4_transport_finish,
 };
 
 void __init xfrm4_state_init(void)
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index c458d0a..3b9eedf 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -23,118 +23,26 @@ int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb)
 
 int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi)
 {
-	int err;
-	__be32 seq;
-	struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
-	struct xfrm_state *x;
-	int xfrm_nr = 0;
-	int decaps = 0;
-	unsigned int nhoff;
-
-	nhoff = IP6CB(skb)->nhoff;
-
-	seq = 0;
-	if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0)
-		goto drop;
-
-	do {
-		struct ipv6hdr *iph = ipv6_hdr(skb);
-
-		if (xfrm_nr == XFRM_MAX_DEPTH)
-			goto drop;
-
-		x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi,
-				      nexthdr, AF_INET6);
-		if (x == NULL)
-			goto drop;
-		spin_lock(&x->lock);
-		if (unlikely(x->km.state != XFRM_STATE_VALID))
-			goto drop_unlock;
-
-		if (x->props.replay_window && xfrm_replay_check(x, seq))
-			goto drop_unlock;
-
-		if (xfrm_state_check_expire(x))
-			goto drop_unlock;
-
-		nexthdr = x->type->input(x, skb);
-		if (nexthdr <= 0)
-			goto drop_unlock;
-
-		skb_network_header(skb)[nhoff] = nexthdr;
-
-		if (x->props.replay_window)
-			xfrm_replay_advance(x, seq);
-
-		x->curlft.bytes += skb->len;
-		x->curlft.packets++;
-
-		spin_unlock(&x->lock);
-
-		xfrm_vec[xfrm_nr++] = x;
-
-		if (x->inner_mode->input(x, skb))
-			goto drop;
-
-		if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) {
-			decaps = 1;
-			break;
-		}
-
-		if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) < 0)
-			goto drop;
-	} while (!err);
-
-	/* Allocate new secpath or COW existing one. */
-	if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
-		struct sec_path *sp;
-		sp = secpath_dup(skb->sp);
-		if (!sp)
-			goto drop;
-		if (skb->sp)
-			secpath_put(skb->sp);
-		skb->sp = sp;
-	}
-
-	if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
-		goto drop;
-
-	memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec,
-	       xfrm_nr * sizeof(xfrm_vec[0]));
-	skb->sp->len += xfrm_nr;
-
-	nf_reset(skb);
+	XFRM_SPI_SKB_CB(skb)->nhoff = IP6CB(skb)->nhoff;
+	XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr);
+	return xfrm_input(skb, nexthdr, spi, 0);
+}
+EXPORT_SYMBOL(xfrm6_rcv_spi);
 
-	if (decaps) {
-		dst_release(skb->dst);
-		skb->dst = NULL;
-		netif_rx(skb);
-		return -1;
-	} else {
+int xfrm6_transport_finish(struct sk_buff *skb, int async)
+{
 #ifdef CONFIG_NETFILTER
-		ipv6_hdr(skb)->payload_len = htons(skb->len);
-		__skb_push(skb, skb->data - skb_network_header(skb));
+	ipv6_hdr(skb)->payload_len = htons(skb->len);
+	__skb_push(skb, skb->data - skb_network_header(skb));
 
-		NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL,
-			ip6_rcv_finish);
-		return -1;
+	NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL,
+		ip6_rcv_finish);
+	return -1;
 #else
-		return 1;
+	return 1;
 #endif
-	}
-
-drop_unlock:
-	spin_unlock(&x->lock);
-	xfrm_state_put(x);
-drop:
-	while (--xfrm_nr >= 0)
-		xfrm_state_put(xfrm_vec[xfrm_nr]);
-	kfree_skb(skb);
-	return -1;
 }
 
-EXPORT_SYMBOL(xfrm6_rcv_spi);
-
 int xfrm6_rcv(struct sk_buff *skb)
 {
 	return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff],
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index bb09e85..00360b5 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -198,6 +198,7 @@ static struct xfrm_state_afinfo xfrm6_state_afinfo = {
 	.output			= xfrm6_output,
 	.extract_input		= xfrm6_extract_input,
 	.extract_output		= xfrm6_extract_output,
+	.transport_finish	= xfrm6_transport_finish,
 };
 
 void __init xfrm6_state_init(void)
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index 4c803f7..b980095 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -9,6 +9,8 @@
 
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/netdevice.h>
+#include <net/dst.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
 
@@ -94,6 +96,117 @@ int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
 }
 EXPORT_SYMBOL(xfrm_prepare_input);
 
+int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
+{
+	int err;
+	__be32 seq;
+	struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
+	struct xfrm_state *x;
+	int xfrm_nr = 0;
+	int decaps = 0;
+	unsigned int nhoff = XFRM_SPI_SKB_CB(skb)->nhoff;
+	unsigned int daddroff = XFRM_SPI_SKB_CB(skb)->daddroff;
+
+	seq = 0;
+	if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0)
+		goto drop;
+
+	do {
+		if (xfrm_nr == XFRM_MAX_DEPTH)
+			goto drop;
+
+		x = xfrm_state_lookup((xfrm_address_t *)
+				      (skb_network_header(skb) + daddroff),
+				      spi, nexthdr, AF_INET);
+		if (x == NULL)
+			goto drop;
+
+		spin_lock(&x->lock);
+		if (unlikely(x->km.state != XFRM_STATE_VALID))
+			goto drop_unlock;
+
+		if ((x->encap ? x->encap->encap_type : 0) != encap_type)
+			goto drop_unlock;
+
+		if (x->props.replay_window && xfrm_replay_check(x, seq))
+			goto drop_unlock;
+
+		if (xfrm_state_check_expire(x))
+			goto drop_unlock;
+
+		nexthdr = x->type->input(x, skb);
+		if (nexthdr <= 0)
+			goto drop_unlock;
+
+		skb_network_header(skb)[nhoff] = nexthdr;
+
+		/* only the first xfrm gets the encap type */
+		encap_type = 0;
+
+		if (x->props.replay_window)
+			xfrm_replay_advance(x, seq);
+
+		x->curlft.bytes += skb->len;
+		x->curlft.packets++;
+
+		spin_unlock(&x->lock);
+
+		xfrm_vec[xfrm_nr++] = x;
+
+		if (x->inner_mode->input(x, skb))
+			goto drop;
+
+		if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) {
+			decaps = 1;
+			break;
+		}
+
+		err = xfrm_parse_spi(skb, nexthdr, &spi, &seq);
+		if (err < 0)
+			goto drop;
+	} while (!err);
+
+	/* Allocate new secpath or COW existing one. */
+
+	if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
+		struct sec_path *sp;
+		sp = secpath_dup(skb->sp);
+		if (!sp)
+			goto drop;
+		if (skb->sp)
+			secpath_put(skb->sp);
+		skb->sp = sp;
+	}
+	if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
+		goto drop;
+
+	memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec,
+	       xfrm_nr * sizeof(xfrm_vec[0]));
+	skb->sp->len += xfrm_nr;
+
+	nf_reset(skb);
+
+	if (decaps) {
+		dst_release(skb->dst);
+		skb->dst = NULL;
+		netif_rx(skb);
+		return 0;
+	} else {
+		return x->inner_mode->afinfo->transport_finish(skb, 0);
+	}
+
+drop_unlock:
+	spin_unlock(&x->lock);
+	xfrm_state_put(x);
+drop:
+	while (--xfrm_nr >= 0)
+		xfrm_state_put(xfrm_vec[xfrm_nr]);
+
+	kfree_skb(skb);
+	return 0;
+}
+EXPORT_SYMBOL(xfrm_input);
+
 void __init xfrm_input_init(void)
 {
 	secpath_cachep = kmem_cache_create("secpath_cache",

^ permalink raw reply related

* [PATCH 23/24] [IPSEC]: Move integrity stat collection into xfrm_input
From: Herbert Xu @ 2007-11-07 14:08 UTC (permalink / raw)
  To: David S. Miller, netdev
In-Reply-To: <20071107140701.GA4685@gondor.apana.org.au>

[IPSEC]: Move integrity stat collection into xfrm_input

Similar to the moving out of the replay processing on the output,
this patch moves the integrity stat collectin from x->type->input
into xfrm_input.

This would eventually allow transforms such as AH/ESP to be lockless.

The error value EBADMSG (currently unused in the crypto layer) is used
to indicate a failed integrity check.  In future this error can be
directly returned by the crypto layer once we switch to aead algorithms.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---

 net/ipv4/ah4.c        |    3 +--
 net/ipv4/esp4.c       |   13 ++++++++-----
 net/ipv6/ah6.c        |    3 +--
 net/ipv6/esp6.c       |    3 +--
 net/xfrm/xfrm_input.c |    5 ++++-
 5 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index 5fc346d..a989d29 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -177,9 +177,8 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
 		err = ah_mac_digest(ahp, skb, ah->auth_data);
 		if (err)
 			goto out;
-		err = -EINVAL;
 		if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) {
-			x->stats.integrity_failed++;
+			err = -EBADMSG;
 			goto out;
 		}
 	}
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index c31bccb..7f1854c 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -162,7 +162,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
 	u8 nexthdr[2];
 	struct scatterlist *sg;
 	int padlen;
-	int err;
+	int err = -EINVAL;
 
 	if (!pskb_may_pull(skb, sizeof(*esph)))
 		goto out;
@@ -182,13 +182,14 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
 			BUG();
 
 		if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
-			x->stats.integrity_failed++;
+			err = -EBADMSG;
 			goto out;
 		}
 	}
 
-	if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0)
+	if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
 		goto out;
+	nfrags = err;
 
 	skb->ip_summed = CHECKSUM_NONE;
 
@@ -201,6 +202,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
 	sg = &esp->sgbuf[0];
 
 	if (unlikely(nfrags > ESP_NUM_FAST_SG)) {
+		err = -ENOMEM;
 		sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
 		if (!sg)
 			goto out;
@@ -213,11 +215,12 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
 	if (unlikely(sg != &esp->sgbuf[0]))
 		kfree(sg);
 	if (unlikely(err))
-		return err;
+		goto out;
 
 	if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2))
 		BUG();
 
+	err = -EINVAL;
 	padlen = nexthdr[0];
 	if (padlen+2 >= elen)
 		goto out;
@@ -271,7 +274,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
 	return nexthdr[1];
 
 out:
-	return -EINVAL;
+	return err;
 }
 
 static u32 esp4_get_mtu(struct xfrm_state *x, int mtu)
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 4eaf550..d4b59ec 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -379,10 +379,9 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
 		err = ah_mac_digest(ahp, skb, ah->auth_data);
 		if (err)
 			goto free_out;
-		err = -EINVAL;
 		if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) {
 			LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n");
-			x->stats.integrity_failed++;
+			err = -EBADMSG;
 			goto free_out;
 		}
 	}
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 7db66f1..c37982b 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -177,8 +177,7 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
 			BUG();
 
 		if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
-			x->stats.integrity_failed++;
-			ret = -EINVAL;
+			ret = -EBADMSG;
 			goto out;
 		}
 	}
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index 587f347..b7d68eb 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -147,8 +147,11 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
 			goto drop_unlock;
 
 		nexthdr = x->type->input(x, skb);
-		if (nexthdr <= 0)
+		if (nexthdr <= 0) {
+			if (nexthdr == -EBADMSG)
+				x->stats.integrity_failed++;
 			goto drop_unlock;
+		}
 
 		skb_network_header(skb)[nhoff] = nexthdr;
 

^ permalink raw reply related

* Re: Endianness problem with u32 classifier hash masks
From: Radu Rendec @ 2007-11-07 14:35 UTC (permalink / raw)
  To: David Miller; +Cc: hadi, jarkao2, netdev
In-Reply-To: <20071107.012220.17723288.davem@davemloft.net>

On Wed, 2007-11-07 at 01:22 -0800, David Miller wrote:
> I've grown impatient and done the work for you :-)  I've applied
> the patch below to my tree, thank you!
> 
> If someone wants to send me the ffs() thing relative to this,
> I'd appreciate it.  Thanks again!

Thanks again for making the patch and applying. I've just tested it and
it works like a charm.

Now moving on to the ffs() thing. I will send the patch later if it
works.

Cheers,
Radu



^ permalink raw reply

* Re: Please pull 'fixes-davem' branch of wireless-2.6
From: Michael Buesch @ 2007-11-07 14:38 UTC (permalink / raw)
  To: John W. Linville; +Cc: davem, jeff, netdev, linux-wireless
In-Reply-To: <20071107001314.GH4440@tuxdriver.com>

On Wednesday 07 November 2007 01:13:14 John W. Linville wrote:
> "ssb: Fix initcall ordering" changes a subsys_initcall to an
> fs_initcall.  This seems like a bit of a hack, but it fixes a real
> problem and I'm not sure what cleaner solution is either reasonable
> or available.  The comment in the patch explains the reasoning for this
> somewhat unique situation.

Well, ssb is not the only subsystem with this special requirement.
Grep for fs_initcall. In my opinion we need another initcall to fix
this issue. I think we need a post_subsys_initcall().
But that really is another issue that we can't decide in netdev.
For now, this fix is harmless and fixes the bug.

-- 
Greetings Michael.

^ permalink raw reply

* RE: [PATCH 00/05] ipv6: RFC4214 Support
From: Templin, Fred L @ 2007-11-07 14:41 UTC (permalink / raw)
  To: David Stevens, Pekka Savola; +Cc: David Miller, netdev, netdev-owner, yoshfuji
In-Reply-To: <OFF45233E5.73C392C8-ON8825738C.00298603-8825738C.002B4AB8@us.ibm.com>

I think I can clear this up. The patent office rejected
SRI's patent application, therefore there are no valid
claims that could prevent ISATAP from being included
in public domain software releases. Indeed, Microsoft,
cisco, and FreeBSD/KAME are shipping ISATAP and have
been doing so for a long time, and I believe there are
also several others.

Fred
fred.l.templin@boeing.com

> -----Original Message-----
> From: David Stevens [mailto:dlstevens@us.ibm.com] 
> Sent: Tuesday, November 06, 2007 11:54 PM
> To: Pekka Savola
> Cc: David Miller; Templin, Fred L; netdev@vger.kernel.org; 
> netdev-owner@vger.kernel.org; yoshfuji@linux-ipv6.org
> Subject: Re: [PATCH 00/05] ipv6: RFC4214 Support
> 
> > give it away on this specific instance.  I'm not sure if you should 
> > attribute to hidden agendas what you can explain by "doing 
> the right 
> > thing" (granted, very few companies do this which may make 
> it suspect, 
> > but still..).
> 
> Pekka,
>         I'm not assuming hidden agendas here; I simply don't know what
> they mean by "no license for implementers."  It doesn't say they
> relinquish *all* licensing, which would be clearer if that's what they
> mean. If implementers, distributors, and users are included, then
> who's left that does need licensing? If that answer really is nobody,
> then why bother with "for implementers."?
>         So, I don't think it's a hidden agenda, I think they said what
> they mean. I just don't know what they mean. :-)
> 
>                                                                 +-DLS
> 
> 

^ permalink raw reply

* Re: [PATCH 1/2] bonding: fix rtnl locking merge error
From: Moni Shoua @ 2007-11-07 14:45 UTC (permalink / raw)
  To: Jay Vosburgh; +Cc: netdev, jgarzik
In-Reply-To: <11943848132752-git-send-email-fubar@us.ibm.com>

Jay Vosburgh wrote:
> 	Looks like I incorrectly merged one of the rtnl lock changes,
> so that one function, bonding_show_active_slave, held rtnl but didn't
> release it, and another, bonding_store_active_slave, never held rtnl but
> did release it.
> 
> 	Fixed so the first function doesn't mess with rtnl, and the
> second correctly acquires and releases rtnl.
> 
> 	Bug reported by Moni Shoua <monis@voltaire.com>

I ran some shallow tests and it seems that the patch fixes  the problem.

thanks


^ permalink raw reply

* Re: bonding / 2.6.24-rc1 issues
From: Moni Shoua @ 2007-11-07 14:52 UTC (permalink / raw)
  To: Or Gerlitz; +Cc: Jay Vosburgh, Roland Dreier, netdev, Moni Levy
In-Reply-To: <4731C2DE.4000701@voltaire.com>

Or Gerlitz wrote:
> Jay, Moni
> 
> I did some tests with 2.6.24-rc1 and the first patch to bonding that Jay
> sent last night to netdev. Basic operation and fail over work fine.
> However, I see some crashes which are somehow related to destroying the
> bond when the slaves are ipoib ones, I don't see similar crashes when
> enslaving ethernet devices (Broadcom Corporation NetXtreme BCM5704
> Gigabit Ethernet (rev 03)), my compressed dot config is attached.
> 
> The first type of oops is when I just do modprobe -r bonding after
> enslavement of the ipoib devices:
> 
> 
> the second type of oops is when I modprobe -r ib_ipoib after
> enslavement. I was not able to test this one with ethernet as the tg3
> code is built into my kernel

I couldn't reproduce the first oops. However, after applying Jay's
fixes for 2.6.24-rc1 I managed to reproduce the second oops.
I will try to look into it.



^ permalink raw reply

* Re: [PATCH 00/05] ipv6: RFC4214 Support
From: Pekka Savola @ 2007-11-07 14:41 UTC (permalink / raw)
  To: David Stevens; +Cc: David Miller, Fred.L.Templin, netdev, yoshfuji
In-Reply-To: <OFF45233E5.73C392C8-ON8825738C.00298603-8825738C.002B4AB8@us.ibm.com>

On Tue, 6 Nov 2007, David Stevens wrote:
>> give it away on this specific instance.  I'm not sure if you should
>> attribute to hidden agendas what you can explain by "doing the right
>> thing" (granted, very few companies do this which may make it suspect,
>> but still..).
>
> Pekka,
>        I'm not assuming hidden agendas here; I simply don't know what
> they mean by "no license for implementers."  It doesn't say they
> relinquish *all* licensing, which would be clearer if that's what they
> mean. If implementers, distributors, and users are included, then
> who's left that does need licensing? If that answer really is nobody,
> then why bother with "for implementers."?
>        So, I don't think it's a hidden agenda, I think they said what
> they mean. I just don't know what they mean. :-)

If you look at the page they used to file the disclosure:

https://datatracker.ietf.org/ipr/new-specific/

You'll notice that they chose the most relaxed option available, and 
all the options only discuss implementers not distributors.

Now, if you look at the background commentary of the subject:

http://tools.ietf.org/html/rfc3905

.. the comment about that particular option is:

    a) No License Required for Implementers: The Patent Holder does not
       require parties to acquire any license to its Necessary Patent
       Claims in order to make, have made, use, import, offer to sell,
       sell, or distribute technology that implements such an IETF
       specification.

Seems clear to me, though someone could argue whether RFC 3905 is 
normative in this context, i.e., whether the person who submitted the 
disclosure understood the comment quoted above and that that's the way 
"no license required for implementers" must be interpreted.

-- 
Pekka Savola                 "You each name yourselves king, yet the
Netcore Oy                    kingdom bleeds."
Systems. Networks. Security. -- George R.R. Martin: A Clash of Kings

^ permalink raw reply

* RE: [2.6 patch] unexport softnet_data
From: Nelson, Shannon @ 2007-11-07 15:01 UTC (permalink / raw)
  To: David Miller
  Cc: bunk, shemminger, netdev, Leech, Christopher, Williams, Dan J
In-Reply-To: <20071106.234113.248978883.davem@davemloft.net>

>From: David Miller [mailto:davem@davemloft.net] 
>Sent: Tuesday, November 06, 2007 11:41 PM
>
>From: "Nelson, Shannon" <shannon.nelson@intel.com>
>Date: Fri, 26 Oct 2007 08:38:55 -0700
>
>> There is no creation of a pinned_list yet in this path, so I 
>don't think
>> this would do us much good.
>
>The pinned list is created in the generic net/ipv4/tcp.c code, not in
>the address family specific code.
>
>So your comments do not apply as a reason for this patch to not go in.
>My patch has been in Linus's tree for weeks, and until you show me a
>real reason why the check shouldn't be there in the ipv6 path, it's
>staying.

Understood.

Thanks,
sln

^ permalink raw reply

* Re: [PATCH] NET: Remove unneeded type cast in skb_truesize_check()
From: Chuck Lever @ 2007-11-07 15:11 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20071105.163320.82203647.davem@davemloft.net>

[-- Attachment #1: Type: text/plain, Size: 1976 bytes --]

David Miller wrote:
> From: Chuck Lever <chuck.lever@oracle.com>
> Date: Mon, 05 Nov 2007 18:59:26 -0500
> 
>> If that's truly the case, document the requirement (perhaps using
>> something the compiler itself can verify) instead of using a clever
>> type cast trick.
> 
> Feel free to submit such a change.

Here's what I propose.

skb->truesize should be an int, not an unsigned int, since you expect 
that it may go below zero.

Explicitly assert that skb->truesize is greater than zero in 
skb_truesize_check().

Explicitly assert that skb->len + sizeof(sk_buff) is less than INT_MAX.

Leave the assertion that's already there, but ensure that the types on 
both side of the comparison are as we expect.

Thoughts?

>> Here's the problem with leaving these little surprises in commonly used 
>> kernel headers.  Suppose the developer of a network driver or network 
>> file system that uses one of these headers wants to employ static code 
>> analysis to identify issues introduced by new patches to their 
>> subsystem.  The tool warnings generated in kernel headers are just 
>> noise, and make using such code analysis difficult.
> 
> Here's the problem with submitting patches fixing non-bugs and
> removing useful assertions from kernel.  I won't apply them.

"removing useful assertions"

The (int) type cast in that assertion is nothing more than a comment. 
The compiler promotes that side of the comparison to match the type on 
the right side, and the explicit type cast is entirely ignored.  So in 
fact, my patch removed nothing but a mistaken assumption.  The assertion 
behaves the same after my patch as it did before.

Thus anyone might be confused at what exactly was being asserted in 
skb_truesize_check().  It's not a question of whether or not I reviewed 
the logic that uses skb->truesize before crafting my patch; I did review 
it.  The fact that skb_truesize_check() never before asserted that 
skb->truesize is greater than zero is not my fault.

[-- Attachment #2: chuck.lever.vcf --]
[-- Type: text/x-vcard, Size: 315 bytes --]

begin:vcard
fn:Chuck Lever
n:Lever;Chuck
org:Oracle Corporation;Corporate Architecture: Linux Projects Group
adr:;;1015 Granger Avenue;Ann Arbor;MI;48104;USA
email;internet:chuck dot lever at nospam oracle dot com
title:Principal Member of Staff
tel;work:+1 248 614 5091
x-mozilla-html:FALSE
version:2.1
end:vcard


^ permalink raw reply

* [PATCH][PACKET] Remove unneeded packet_socks_nr variable
From: Pavel Emelyanov @ 2007-11-07 15:32 UTC (permalink / raw)
  To: David Miller; +Cc: Linux Netdev List, devel

This one is used only under ifdef PACKET_REFCNT_DEBUG in
printk and is not needed otherwise. So hide all this stuff
under the PACKET_REFCNT_DEBUG.

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>

---

diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 4cb2dfb..e6a96ee 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -139,8 +139,30 @@ dev->hard_header == NULL (ll header is added by device, we cannot control it)
 static HLIST_HEAD(packet_sklist);
 static DEFINE_RWLOCK(packet_sklist_lock);
 
+#ifdef PACKET_REFCNT_DEBUG
 static atomic_t packet_socks_nr;
 
+static void packet_sock_inc(void)
+{
+	atomic_inc(&packet_socks_nr);
+}
+
+static void packet_sock_dec(void)
+{
+	atomic_dec(&packet_socks_nr);
+	printk(KERN_DEBUG "PACKET socket %p is free, %d are alive\n",
+			sk, atomic_read(&packet_socks_nr));
+}
+#else
+static inline void packet_sock_inc(void)
+{
+}
+
+static inline void packet_sock_dec(void)
+{
+}
+#endif
+
 
 /* Private packet socket structures. */
 
@@ -236,10 +258,7 @@ static void packet_sock_destruct(struct sock *sk)
 		return;
 	}
 
-	atomic_dec(&packet_socks_nr);
-#ifdef PACKET_REFCNT_DEBUG
-	printk(KERN_DEBUG "PACKET socket %p is free, %d are alive\n", sk, atomic_read(&packet_socks_nr));
-#endif
+	packet_sock_dec();
 }
 
 
@@ -1010,7 +1029,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol)
 	po->num = proto;
 
 	sk->sk_destruct = packet_sock_destruct;
-	atomic_inc(&packet_socks_nr);
+	packet_sock_inc();
 
 	/*
 	 *	Attach a protocol block
-- 
1.5.3.4


^ permalink raw reply related

* Re: [PATCH][PACKET] Remove unneeded packet_socks_nr variable
From: Arnaldo Carvalho de Melo @ 2007-11-07 15:50 UTC (permalink / raw)
  To: Pavel Emelyanov; +Cc: David Miller, Linux Netdev List, devel
In-Reply-To: <4731DAA3.7060306@openvz.org>

Em Wed, Nov 07, 2007 at 06:32:51PM +0300, Pavel Emelyanov escreveu:
> This one is used only under ifdef PACKET_REFCNT_DEBUG in
> printk and is not needed otherwise. So hide all this stuff
> under the PACKET_REFCNT_DEBUG.
> 
> Signed-off-by: Pavel Emelyanov <xemul@openvz.org>

Look at sk_refcnt_debug_inc, etc and you'll se a more standard way. I
forgot to make this when making all protocol families use sk_prot, even
if just partially :-)

- Arnaldo

^ permalink raw reply

* Re: [PATCH][PACKET] Remove unneeded packet_socks_nr variable
From: Arnaldo Carvalho de Melo @ 2007-11-07 15:53 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Pavel Emelyanov, David Miller,
	Linux Netdev List, devel
In-Reply-To: <20071107155004.GI27345@ghostprotocols.net>

Em Wed, Nov 07, 2007 at 01:50:04PM -0200, Arnaldo Carvalho de Melo escreveu:
> Em Wed, Nov 07, 2007 at 06:32:51PM +0300, Pavel Emelyanov escreveu:
> > This one is used only under ifdef PACKET_REFCNT_DEBUG in
> > printk and is not needed otherwise. So hide all this stuff
> > under the PACKET_REFCNT_DEBUG.
> > 
> > Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
> 
> Look at sk_refcnt_debug_inc, etc and you'll se a more standard way. I
> forgot to make this when making all protocol families use sk_prot, even
> if just partially :-)

As a bonus you'll get this information on /proc/net/protocols, removing
'-1' from PACKET column for "sockets".

- Arnaldo

^ permalink raw reply

* Re: [PATCH 02/05] ipv6: RFC4214 Support
From: Ingo Oeser @ 2007-11-07 15:58 UTC (permalink / raw)
  To: Templin, Fred L; +Cc: netdev
In-Reply-To: <39C363776A4E8C4A94691D2BD9D1C9A1029EDBE3@XCH-NW-7V2.nw.nos.boeing.com>

Hi Fred,

some comments.

Templin, Fred L schrieb:
> From: Fred L. Templin <fred.l.templin@boeing.com>
> 
> This is experimental support for the Intra-Site Automatic
> Tunnel Addressing Protocol (ISATAP) per RFC4214. It uses
> the SIT module, and is configured using the unmodified
> "ip" utility with device names beginning with: "isatap".
> 
> The following diffs are specific to the Linux 2.6.23
> kernel distribution.
> 
> Signed-off-by: Fred L. Templin <fred.l.templin@boeing.com>
> 
> ---
> 
> --- linux-2.6.23/include/net/addrconf.h.orig	2007-10-09
> 13:31:38.000000000 -0700
> +++ linux-2.6.23/include/net/addrconf.h	2007-10-26 10:49:40.000000000
> -0700
> @@ -241,6 +241,34 @@ static inline int ipv6_addr_is_ll_all_ro
>  		addr->s6_addr32[3] == htonl(0x00000002));
>  }
>  
> +#if defined(CONFIG_IPV6_ISATAP)
> +static inline int ipv6_isatap_eui64(u8 *eui, __be32 *addr)
"addr" is only used for reading, not writing. No need to pass it as a pointer.

> +{
> +	__be32 ipv4 = ntohl(*addr);

ntohl(be32_value) != be32_value, so the _be32 attribution of ipv4 
is wrong here and sparse will scream.

> +
> +	eui[0] = 0;
> +
> +	/* Check for RFC3330 global address ranges */
> +	if (((ipv4 >= 0x01000000) && (ipv4 < 0x0a000000)) ||
> +	    ((ipv4 >= 0x0b000000) && (ipv4 < 0x7f000000)) ||
> +	    ((ipv4 >= 0x80000000) && (ipv4 < 0xa9fe0000)) ||
> +	    ((ipv4 >= 0xa9ff0000) && (ipv4 < 0xac100000)) ||
> +	    ((ipv4 >= 0xac200000) && (ipv4 < 0xc0a80000)) ||
> +	    ((ipv4 >= 0xc0a90000) && (ipv4 < 0xc6120000)) ||
> +	    ((ipv4 >= 0xc6140000) && (ipv4 < 0xe0000000))) eui[0] |=
> 0x2;
> +

Instead of converting network to host byte order at runtime 
and comparing the results to constants, let the compiler convert
the constants to network byte order and compare in network order.

so use:

 if (((*addr >= htonl(0x01000000)) && (*addr < htonl(0x0a000000))) || ....

instead. The compiler will notice that "0x01000000" is a constant and will
use "_constant_htonl()" automatically.


> +	eui[1] = 0; eui[2] = 0x5E; eui[3] = 0xFE;
> +	memcpy (eui+4, addr, 4);
> +	return (0);
> +}

Nitpick: 
	"return" is not a function. Please write "return 0;" instead.

> +
> +static inline int ipv6_addr_is_isatap(const struct in6_addr *addr)
> +{
> +       return (addr->s6_addr32[2] == __constant_htonl(0x02005EFE) ||
> +               addr->s6_addr32[2] == __constant_htonl(0x00005EFE));
> +}
> +#endif

The compiler will notice that "0x01000000" is a constant and will
use "_constant_htonl()" automatically. Please use simply htonl().


Best Regards

Ingo Oeser

^ permalink raw reply

* RE: [PATCH 02/05] ipv6: RFC4214 Support
From: Templin, Fred L @ 2007-11-07 16:12 UTC (permalink / raw)
  To: Ingo Oeser; +Cc: netdev
In-Reply-To: <200711071658.59478.netdev@axxeo.de>

Thanks for these, Ingo. Will fix and test immediately.

Fred
fred.l.templin@boeing.com 

> -----Original Message-----
> From: Ingo Oeser [mailto:netdev@axxeo.de] 
> Sent: Wednesday, November 07, 2007 7:59 AM
> To: Templin, Fred L
> Cc: netdev@vger.kernel.org
> Subject: Re: [PATCH 02/05] ipv6: RFC4214 Support
> 
> Hi Fred,
> 
> some comments.
> 
> Templin, Fred L schrieb:
> > From: Fred L. Templin <fred.l.templin@boeing.com>
> > 
> > This is experimental support for the Intra-Site Automatic
> > Tunnel Addressing Protocol (ISATAP) per RFC4214. It uses
> > the SIT module, and is configured using the unmodified
> > "ip" utility with device names beginning with: "isatap".
> > 
> > The following diffs are specific to the Linux 2.6.23
> > kernel distribution.
> > 
> > Signed-off-by: Fred L. Templin <fred.l.templin@boeing.com>
> > 
> > ---
> > 
> > --- linux-2.6.23/include/net/addrconf.h.orig	2007-10-09
> > 13:31:38.000000000 -0700
> > +++ linux-2.6.23/include/net/addrconf.h	2007-10-26 
> 10:49:40.000000000
> > -0700
> > @@ -241,6 +241,34 @@ static inline int ipv6_addr_is_ll_all_ro
> >  		addr->s6_addr32[3] == htonl(0x00000002));
> >  }
> >  
> > +#if defined(CONFIG_IPV6_ISATAP)
> > +static inline int ipv6_isatap_eui64(u8 *eui, __be32 *addr)
> "addr" is only used for reading, not writing. No need to pass 
> it as a pointer.
> 
> > +{
> > +	__be32 ipv4 = ntohl(*addr);
> 
> ntohl(be32_value) != be32_value, so the _be32 attribution of ipv4 
> is wrong here and sparse will scream.
> 
> > +
> > +	eui[0] = 0;
> > +
> > +	/* Check for RFC3330 global address ranges */
> > +	if (((ipv4 >= 0x01000000) && (ipv4 < 0x0a000000)) ||
> > +	    ((ipv4 >= 0x0b000000) && (ipv4 < 0x7f000000)) ||
> > +	    ((ipv4 >= 0x80000000) && (ipv4 < 0xa9fe0000)) ||
> > +	    ((ipv4 >= 0xa9ff0000) && (ipv4 < 0xac100000)) ||
> > +	    ((ipv4 >= 0xac200000) && (ipv4 < 0xc0a80000)) ||
> > +	    ((ipv4 >= 0xc0a90000) && (ipv4 < 0xc6120000)) ||
> > +	    ((ipv4 >= 0xc6140000) && (ipv4 < 0xe0000000))) eui[0] |=
> > 0x2;
> > +
> 
> Instead of converting network to host byte order at runtime 
> and comparing the results to constants, let the compiler convert
> the constants to network byte order and compare in network order.
> 
> so use:
> 
>  if (((*addr >= htonl(0x01000000)) && (*addr < 
> htonl(0x0a000000))) || ....
> 
> instead. The compiler will notice that "0x01000000" is a 
> constant and will
> use "_constant_htonl()" automatically.
> 
> 
> > +	eui[1] = 0; eui[2] = 0x5E; eui[3] = 0xFE;
> > +	memcpy (eui+4, addr, 4);
> > +	return (0);
> > +}
> 
> Nitpick: 
> 	"return" is not a function. Please write "return 0;" instead.
> 
> > +
> > +static inline int ipv6_addr_is_isatap(const struct in6_addr *addr)
> > +{
> > +       return (addr->s6_addr32[2] == 
> __constant_htonl(0x02005EFE) ||
> > +               addr->s6_addr32[2] == __constant_htonl(0x00005EFE));
> > +}
> > +#endif
> 
> The compiler will notice that "0x01000000" is a constant and will
> use "_constant_htonl()" automatically. Please use simply htonl().
> 
> 
> Best Regards
> 
> Ingo Oeser
> 

^ permalink raw reply

* Re: [PATCH][PACKET] Remove unneeded packet_socks_nr variable
From: Pavel Emelyanov @ 2007-11-07 16:16 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, David Miller, Linux Netdev List, devel
In-Reply-To: <20071107155301.GJ27345@ghostprotocols.net>

Arnaldo Carvalho de Melo wrote:
> Em Wed, Nov 07, 2007 at 01:50:04PM -0200, Arnaldo Carvalho de Melo escreveu:
>> Em Wed, Nov 07, 2007 at 06:32:51PM +0300, Pavel Emelyanov escreveu:
>>> This one is used only under ifdef PACKET_REFCNT_DEBUG in
>>> printk and is not needed otherwise. So hide all this stuff
>>> under the PACKET_REFCNT_DEBUG.
>>>
>>> Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
>> Look at sk_refcnt_debug_inc, etc and you'll se a more standard way. I
>> forgot to make this when making all protocol families use sk_prot, even
>> if just partially :-)
> 
> As a bonus you'll get this information on /proc/net/protocols, removing
> '-1' from PACKET column for "sockets".

Hm... I actually thought about this, but I decided that packet
sockets were not accounted in this way deliberately.

So, shall I break this "compatibility" (-1 in proc) and provide
a packet socket number in this file?

> - Arnaldo

Thanks,
Pavel

^ permalink raw reply

* [PATCH 0/2] generalize {DEFINE|REF}_PROTO_INUSE was Re: [PATCH 0/4] NET : struct proto diet
From: Arnaldo Carvalho de Melo @ 2007-11-07 16:16 UTC (permalink / raw)
  To: David Miller; +Cc: dada1, netdev
In-Reply-To: <20071105.234306.200631818.davem@davemloft.net>

Em Mon, Nov 05, 2007 at 11:43:06PM -0800, David Miller escreveu:
> From: Eric Dumazet <dada1@cosmosbay.com>
> Date: Mon, 05 Nov 2007 18:52:32 +0100
> 
> > This patch series does some cleanup and optimization.
> > 
> > [PATCH 1/4] NET : defines an infrastructure to keep 'inuse' changes in 
> > an efficent SMP/NUMA way.
> > [PATCH 2/4] NET : makes ipv4 use the  {DEFINE|REF}_PROTO_INUSE 
> > infrastructure
> > [PATCH 3/4] NET : makes ipv6 use the  {DEFINE|REF}_PROTO_INUSE 
> > infrastructure
> > [PATCH 4/4] NET : makes sctp use the  {DEFINE|REF}_PROTO_INUSE 
> > infrastructure
> 
> Applied, and because I love DCCP I added the following
> patch on top.

Thank you dudes. I found it so nice that I can't help but wonder if this
wouldn't provide for an interesting "class", because this has nothing
that is specific to network protocols, struct proto is just one user...

Lemme try to do this right now:

David,

	Please consider pulling from:

master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6

- Arnaldo

^ permalink raw reply

* [PATCH 1/2] [LIB]: Introduce struct pcounter
From: Arnaldo Carvalho de Melo @ 2007-11-07 16:16 UTC (permalink / raw)
  To: David S. Miller; +Cc: dada1, netdev

This just generalises what was introduced by Eric Dumazet for the struct proto
inuse field in 286ab3d46058840d68e5d7d52e316c1f7e98c59f:

    [NET]: Define infrastructure to keep 'inuse' changes in an efficent SMP/NUMA way.

Please look at the comment in there to see the rationale.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 include/linux/pcounter.h |  102 ++++++++++++++++++++++++++++++++++++++++++++++
 lib/Makefile             |    1 +
 lib/pcounter.c           |   26 ++++++++++++
 3 files changed, 129 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/pcounter.h
 create mode 100644 lib/pcounter.c

diff --git a/include/linux/pcounter.h b/include/linux/pcounter.h
new file mode 100644
index 0000000..3d3891b
--- /dev/null
+++ b/include/linux/pcounter.h
@@ -0,0 +1,102 @@
+#ifndef __LINUX_PCOUNTER_H
+#define __LINUX_PCOUNTER_H
+
+struct pcounter {
+#ifdef CONFIG_SMP
+	void		(*add)(struct pcounter *self, int inc);
+	int		(*getval)(const struct pcounter *self);
+	int		*per_cpu_values;
+#else
+	int		val;
+#endif
+};
+
+/*
+ * Special macros to let pcounters use a fast version of {getvalue|add}
+ * using a static percpu variable per pcounter instead of an allocated one,
+ * saving one dereference.
+ * This might be changed if/when dynamic percpu vars become fast.
+ */
+#ifdef CONFIG_SMP
+#include <linux/cpumask.h>
+#include <linux/percpu.h>
+
+#define DEFINE_PCOUNTER(NAME)					\
+static DEFINE_PER_CPU(int, NAME##_pcounter_values);		\
+static void NAME##_pcounter_add(struct pcounter *self, int inc)	\
+{								\
+       __get_cpu_var(NAME##_pcounter_values) += inc;		\
+}								\
+								\
+static int NAME##_pcounter_getval(const struct pcounter *self)	\
+{								\
+       int res = 0, cpu;					\
+								\
+       for_each_possible_cpu(cpu)				\
+               res += per_cpu(NAME##_pcounter_values, cpu);	\
+       return res;						\
+}
+								
+#define PCOUNTER_MEMBER_INITIALIZER(NAME, MEMBER)		\
+	MEMBER = {						\
+		.add	= NAME##_pcounter_add,			\
+		.getval = NAME##_pcounter_getval,		\
+	}
+
+extern void pcounter_def_add(struct pcounter *self, int inc);
+extern int pcounter_def_getval(const struct pcounter *self);
+
+static inline int pcounter_alloc(struct pcounter *self)
+{
+	int rc = 0;
+	if (self->add == NULL) {
+		self->per_cpu_values = alloc_percpu(int);
+		if (self->per_cpu_values != NULL) {
+			self->add    = pcounter_def_add;
+			self->getval = pcounter_def_getval;
+		} else
+			rc = 1;
+	}
+	return rc;
+}
+
+static inline void pcounter_free(struct pcounter *self)
+{
+	if (self->per_cpu_values != NULL) {
+		free_percpu(self->per_cpu_values);
+		self->per_cpu_values = NULL;
+		self->getval = NULL;
+		self->add = NULL;
+	}
+}
+
+static inline void pcounter_add(struct pcounter *self, int inc)
+{
+	self->add(self, inc);
+}
+
+static inline int pcounter_getval(const struct pcounter *self)
+{
+	return self->getval(self);
+}
+
+#else /* CONFIG_SMP */
+
+static inline void pcounter_add(struct pcounter *self, int inc)
+{
+	self->value += inc;
+}
+
+static inline int pcounter_getval(const struct pcounter *self)
+{
+	return self->val;
+}
+
+#define DEFINE_PCOUNTER(NAME)
+#define PCOUNTER_MEMBER_INITIALIZER(NAME, MEMBER)
+#define pcounter_alloc(self) 0
+#define pcounter_free(self)
+
+#endif /* CONFIG_SMP */
+
+#endif /* __LINUX_PCOUNTER_H */
diff --git a/lib/Makefile b/lib/Makefile
index 3a0983b..0fe94ec 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_TEXTSEARCH_KMP) += ts_kmp.o
 obj-$(CONFIG_TEXTSEARCH_BM) += ts_bm.o
 obj-$(CONFIG_TEXTSEARCH_FSM) += ts_fsm.o
 obj-$(CONFIG_SMP) += percpu_counter.o
+obj-$(CONFIG_SMP) += pcounter.o
 obj-$(CONFIG_AUDIT_GENERIC) += audit.o
 
 obj-$(CONFIG_SWIOTLB) += swiotlb.o
diff --git a/lib/pcounter.c b/lib/pcounter.c
new file mode 100644
index 0000000..e89880e
--- /dev/null
+++ b/lib/pcounter.c
@@ -0,0 +1,26 @@
+/*
+ * Define default pcounter functions 
+ * Note that often used pcounters use dedicated functions to get a speed increase.
+ * (see DEFINE_PCOUNTER/REF_PCOUNTER_MEMBER)
+ */
+
+#include <linux/module.h>
+#include <linux/pcounter.h>
+#include <linux/smp.h>
+
+void pcounter_def_add(struct pcounter *self, int inc)
+{
+	per_cpu_ptr(self->per_cpu_values, smp_processor_id())[0] += inc;
+}
+
+EXPORT_SYMBOL_GPL(pcounter_def_add);
+
+int pcounter_def_getval(const struct pcounter *self)
+{
+	int res = 0, cpu;
+	for_each_possible_cpu(cpu)
+		res += per_cpu_ptr(self->per_cpu_values, cpu)[0];
+	return res;
+}
+
+EXPORT_SYMBOL_GPL(pcounter_def_getval);
-- 
1.5.3.4


^ permalink raw reply related

* RE: [PATCH 04/05] ipv6: RFC4214 Support
From: Templin, Fred L @ 2007-11-07 16:16 UTC (permalink / raw)
  To: netdev
In-Reply-To: <39C363776A4E8C4A94691D2BD9D1C9A1029EDBE5@XCH-NW-7V2.nw.nos.boeing.com>

> @@ -395,8 +451,6 @@ static int ipip6_rcv(struct sk_buff *skb
>  	}
>  
>  	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
> -	kfree_skb(skb);
> -	read_unlock(&ipip6_lock);
>  out:
>  	return 0;
>  }

Note that the above lines were incorrectly deleted.
This has been fixed and tested.

Fred
fred.l.templin@boeing.com

> -----Original Message-----
> From: Templin, Fred L 
> Sent: Tuesday, November 06, 2007 5:16 PM
> To: netdev@vger.kernel.org
> Subject: [PATCH 04/05] ipv6: RFC4214 Support
> 
> From: Fred L. Templin <fred.l.templin@boeing.com>
> 
> This is experimental support for the Intra-Site Automatic
> Tunnel Addressing Protocol (ISATAP) per RFC4214. It uses
> the SIT module, and is configured using the unmodified
> "ip" utility with device names beginning with: "isatap".
> 
> The following diffs are specific to the Linux 2.6.23
> kernel distribution.
> 
> Signed-off-by: Fred L. Templin <fred.l.templin@boeing.com>
> 
> ---
> 
> --- linux-2.6.23/net/ipv6/sit.c.orig	2007-10-09 13:31:38.000000000
> -0700
> +++ linux-2.6.23/net/ipv6/sit.c	2007-11-06 
> 15:32:27.000000000 -0800
> @@ -16,6 +16,7 @@
>   *	Changes:
>   * Roger Venning <r.venning@telstra.com>:	6to4 support
>   * Nate Thompson <nate@thebog.net>:		6to4 support
> + * Fred L. Templin <fltemplin@acm.org>:		isatap support
>   */
>  
>  #include <linux/module.h>
> @@ -154,6 +155,14 @@ static struct ip_tunnel * ipip6_tunnel_l
>  	struct net_device *dev;
>  	char name[IFNAMSIZ];
>  
> +#if defined(CONFIG_IPV6_ISATAP)
> +	/* ISATAP (RFC4214) - router address in daddr */
> +	if (!strncmp(parms->name, "isatap", 6)) {
> +		parms->i_key = parms->iph.daddr;
> +		parms->iph.daddr = remote = 0;
> +	}
> +#endif
> +
>  	for (tp = __ipip6_bucket(parms); (t = *tp) != NULL; tp =
> &t->next) {
>  		if (local == t->parms.iph.saddr && remote ==
> t->parms.iph.daddr)
>  			return t;
> @@ -182,6 +191,11 @@ static struct ip_tunnel * ipip6_tunnel_l
>  	dev->init = ipip6_tunnel_init;
>  	nt->parms = *parms;
>  
> +#if defined(CONFIG_IPV6_ISATAP)
> +	if (!strncmp(dev->name, "isatap", 6))
> +		dev->priv_flags |= IFF_ISATAP;
> +#endif
> +
>  	if (register_netdevice(dev) < 0) {
>  		free_netdev(dev);
>  		goto failed;
> @@ -382,6 +396,48 @@ static int ipip6_rcv(struct sk_buff *skb
>  		IPCB(skb)->flags = 0;
>  		skb->protocol = htons(ETH_P_IPV6);
>  		skb->pkt_type = PACKET_HOST;
> +#if defined(CONFIG_IPV6_ISATAP)
> +		/* ISATAP (RFC4214) - check source address */
> +		if (tunnel->dev->priv_flags & IFF_ISATAP) {
> +		    struct neighbour *neigh;
> +		    struct dst_entry *dst;
> +		    struct flowi fl;
> +		    struct in6_addr *addr6;
> +		    struct ipv6hdr *iph6;
> +
> +		    /* from ISATAP router */
> +		    if (iph->saddr == tunnel->parms.i_key) goto accept;
> +
> +		    iph6 = ipv6_hdr(skb);
> +		    addr6 = &iph6->saddr;
> +
> +		    /* from legitimate previous hop */
> +		    memset(&fl, 0, sizeof(fl));
> +		    fl.proto = iph6->nexthdr;
> +		    ipv6_addr_copy(&fl.fl6_dst, addr6);
> +		    fl.oif = tunnel->dev->ifindex;
> +		    security_skb_classify_flow(skb, &fl);
> +
> +		    if (!(dst = ip6_route_output(NULL, &fl)) ||
> +			 (dst->dev != tunnel->dev) ||
> +			 ((neigh = dst->neighbour) == NULL))
> +			goto drop;
> +
> +		    addr6 = (struct in6_addr*)&neigh->primary_key;
> +
> +		    if (!(ipv6_addr_is_isatap(addr6)) ||
> +			(addr6->s6_addr32[3] != iph->saddr)) {
> +drop:
> +			tunnel->stat.rx_errors++;
> +			dst_release(dst);
> +			kfree_skb(skb);
> +			read_unlock(&ipip6_lock);
> +			return 0;
> +		    }
> +		    dst_release(dst);
> +		}
> +accept:
> +#endif
>  		tunnel->stat.rx_packets++;
>  		tunnel->stat.rx_bytes += skb->len;
>  		skb->dev = tunnel->dev;
> @@ -395,8 +451,6 @@ static int ipip6_rcv(struct sk_buff *skb
>  	}
>  
>  	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
> -	kfree_skb(skb);
> -	read_unlock(&ipip6_lock);
>  out:
>  	return 0;
>  }
> @@ -444,6 +498,31 @@ static int ipip6_tunnel_xmit(struct sk_b
>  	if (skb->protocol != htons(ETH_P_IPV6))
>  		goto tx_error;
>  
> +#if defined(CONFIG_IPV6_ISATAP)
> +	/* ISATAP (RFC4214) - must come before 6to4 */
> +	if (dev->priv_flags & IFF_ISATAP) {
> +		struct neighbour *neigh = NULL;
> +
> +		if (skb->dst)
> +			neigh = skb->dst->neighbour;
> +
> +		if (neigh == NULL) {
> +			if (net_ratelimit())
> +		    		printk(KERN_DEBUG "sit: nexthop ==
> NULL\n");
> +			goto tx_error;
> +	    	}
> +
> +		addr6 = (struct in6_addr*)&neigh->primary_key;
> +		addr_type = ipv6_addr_type(addr6);
> +
> +		if ((addr_type & IPV6_ADDR_UNICAST) &&
> +		     ipv6_addr_is_isatap(addr6))
> +			dst = addr6->s6_addr32[3];
> +		else
> +			goto tx_error;
> +	}
> +#endif	/* CONFIG_IPV6_ISATAP */
> +
>  	if (!dst)
>  		dst = try_6to4(&iph6->daddr);
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply

* [PATCH 2/2] [NET] proto: Use pcounters for the inuse field
From: Arnaldo Carvalho de Melo @ 2007-11-07 16:16 UTC (permalink / raw)
  To: David S. Miller; +Cc: dada1, netdev

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 include/net/sock.h |   59 ++++++-------------------------------------------
 net/core/sock.c    |   61 +++++----------------------------------------------
 2 files changed, 14 insertions(+), 106 deletions(-)

diff --git a/include/net/sock.h b/include/net/sock.h
index 5504fb9..94f4819 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -47,6 +47,7 @@
 #include <linux/module.h>
 #include <linux/lockdep.h>
 #include <linux/netdevice.h>
+#include <linux/pcounter.h>
 #include <linux/skbuff.h>	/* struct sk_buff */
 #include <linux/mm.h>
 #include <linux/security.h>
@@ -560,14 +561,9 @@ struct proto {
 	void			(*unhash)(struct sock *sk);
 	int			(*get_port)(struct sock *sk, unsigned short snum);
 
-#ifdef CONFIG_SMP
 	/* Keeping track of sockets in use */
-	void			(*inuse_add)(struct proto *prot, int inc);
-	int			(*inuse_getval)(const struct proto *prot);
-	int			*inuse_ptr;
-#else
-	int			inuse;
-#endif
+	struct pcounter		inuse;
+
 	/* Memory pressure */
 	void			(*enter_memory_pressure)(void);
 	atomic_t		*memory_allocated;	/* Current allocated memory. */
@@ -602,35 +598,8 @@ struct proto {
 #endif
 };
 
-/*
- * Special macros to let protos use a fast version of inuse{get|add}
- * using a static percpu variable per proto instead of an allocated one,
- * saving one dereference.
- * This might be changed if/when dynamic percpu vars become fast.
- */
-#ifdef CONFIG_SMP
-# define DEFINE_PROTO_INUSE(NAME)			\
-static DEFINE_PER_CPU(int, NAME##_inuse);		\
-static void NAME##_inuse_add(struct proto *prot, int inc)	\
-{							\
-	__get_cpu_var(NAME##_inuse) += inc;		\
-}							\
-							\
-static int NAME##_inuse_getval(const struct proto *prot)\
-{							\
-	int res = 0, cpu;				\
-							\
-	for_each_possible_cpu(cpu)			\
-		res += per_cpu(NAME##_inuse, cpu);	\
-	return res;					\
-}
-# define REF_PROTO_INUSE(NAME)				\
-	.inuse_add = NAME##_inuse_add,			\
-	.inuse_getval = NAME##_inuse_getval,
-#else
-# define DEFINE_PROTO_INUSE(NAME)
-# define REF_PROTO_INUSE(NAME)
-#endif
+#define DEFINE_PROTO_INUSE(NAME) DEFINE_PCOUNTER(NAME)
+#define REF_PROTO_INUSE(NAME) PCOUNTER_MEMBER_INITIALIZER(NAME, .inuse)
 
 extern int proto_register(struct proto *prot, int alloc_slab);
 extern void proto_unregister(struct proto *prot);
@@ -663,29 +632,17 @@ static inline void sk_refcnt_debug_release(const struct sock *sk)
 /* Called with local bh disabled */
 static __inline__ void sock_prot_inc_use(struct proto *prot)
 {
-#ifdef CONFIG_SMP
-	prot->inuse_add(prot, 1);
-#else
-	prot->inuse++;
-#endif
+	pcounter_add(&prot->inuse, 1);
 }
 
 static __inline__ void sock_prot_dec_use(struct proto *prot)
 {
-#ifdef CONFIG_SMP
-	prot->inuse_add(prot, -1);
-#else
-	prot->inuse--;
-#endif
+	pcounter_add(&prot->inuse, -1);
 }
 
 static __inline__ int sock_prot_inuse(struct proto *proto)
 {
-#ifdef CONFIG_SMP
-	return proto->inuse_getval(proto);
-#else
-	return proto->inuse;
-#endif
+	return pcounter_getval(&proto->inuse);
 }
 
 /* With per-bucket locks this operation is not-atomic, so that
diff --git a/net/core/sock.c b/net/core/sock.c
index 8fc2f84..1f600e8 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1801,65 +1801,15 @@ EXPORT_SYMBOL(sk_common_release);
 static DEFINE_RWLOCK(proto_list_lock);
 static LIST_HEAD(proto_list);
 
-#ifdef CONFIG_SMP
-/*
- * Define default functions to keep track of inuse sockets per protocol
- * Note that often used protocols use dedicated functions to get a speed increase.
- * (see DEFINE_PROTO_INUSE/REF_PROTO_INUSE)
- */
-static void inuse_add(struct proto *prot, int inc)
-{
-	per_cpu_ptr(prot->inuse_ptr, smp_processor_id())[0] += inc;
-}
-
-static int inuse_get(const struct proto *prot)
-{
-	int res = 0, cpu;
-	for_each_possible_cpu(cpu)
-		res += per_cpu_ptr(prot->inuse_ptr, cpu)[0];
-	return res;
-}
-
-static int inuse_init(struct proto *prot)
-{
-	if (!prot->inuse_getval || !prot->inuse_add) {
-		prot->inuse_ptr = alloc_percpu(int);
-		if (prot->inuse_ptr == NULL)
-			return -ENOBUFS;
-
-		prot->inuse_getval = inuse_get;
-		prot->inuse_add = inuse_add;
-	}
-	return 0;
-}
-
-static void inuse_fini(struct proto *prot)
-{
-	if (prot->inuse_ptr != NULL) {
-		free_percpu(prot->inuse_ptr);
-		prot->inuse_ptr = NULL;
-		prot->inuse_getval = NULL;
-		prot->inuse_add = NULL;
-	}
-}
-#else
-static inline int inuse_init(struct proto *prot)
-{
-	return 0;
-}
-
-static inline void inuse_fini(struct proto *prot)
-{
-}
-#endif
-
 int proto_register(struct proto *prot, int alloc_slab)
 {
 	char *request_sock_slab_name = NULL;
 	char *timewait_sock_slab_name;
 
-	if (inuse_init(prot))
+	if (pcounter_alloc(&prot->inuse) != 0) {
+		printk(KERN_CRIT "%s: Can't alloc inuse counters!\n", prot->name);
 		goto out;
+	}
 
 	if (alloc_slab) {
 		prot->slab = kmem_cache_create(prot->name, prot->obj_size, 0,
@@ -1927,7 +1877,7 @@ out_free_sock_slab:
 	kmem_cache_destroy(prot->slab);
 	prot->slab = NULL;
 out_free_inuse:
-	inuse_fini(prot);
+	pcounter_free(&prot->inuse);
 out:
 	return -ENOBUFS;
 }
@@ -1940,7 +1890,8 @@ void proto_unregister(struct proto *prot)
 	list_del(&prot->node);
 	write_unlock(&proto_list_lock);
 
-	inuse_fini(prot);
+	pcounter_free(&prot->inuse);
+
 	if (prot->slab != NULL) {
 		kmem_cache_destroy(prot->slab);
 		prot->slab = NULL;
-- 
1.5.3.4


^ permalink raw reply related

* Re: [PATCH 13/24] [IPSEC]: Move x->outer_mode->output out of locked section
From: Ingo Oeser @ 2007-11-07 16:17 UTC (permalink / raw)
  To: Herbert Xu; +Cc: David S. Miller, netdev
In-Reply-To: <E1Ipla1-0001Hb-00@gondolin.me.apana.org.au>

Hi Herbert,

Herbert Xu schrieb:
> diff --git a/net/ipv6/xfrm6_mode_ro.c b/net/ipv6/xfrm6_mode_ro.c
> index a7bc8c6..4a01cb3 100644
> --- a/net/ipv6/xfrm6_mode_ro.c
> +++ b/net/ipv6/xfrm6_mode_ro.c
> @@ -53,7 +54,9 @@ static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb)
>  	__skb_pull(skb, hdr_len);
>  	memmove(ipv6_hdr(skb), iph, hdr_len);
>  
> +	spin_lock_bh(&x->lock);
>  	x->lastused = get_seconds();
> +	spin_unlock_bh(&x->lock);
>  
>  	return 0;
>  }

Can you move the retrieval of the seconds outside the spinlock?

e.g.

tmp = get_seconds();
spin_lock_bh(&x->lock);
x->lastused = tmp;
spin_unlock_bh(&x->lock);

or is it not really worth it?

Best Regards

Ingo Oeser

^ permalink raw reply

* [PATCH] ethtool: add support for supporting 10000baseT
From: Auke Kok @ 2007-11-07 16:24 UTC (permalink / raw)
  To: jeff; +Cc: netdev, jesse.brandeburg, auke-jan.h.kok

From: Jesse Brandeburg <jesse.brandeburg@intel.com>

there is missing support in ethtool for reporting 10000baseT
as SUPPORTED_10000baseT_Full.  The code seems to be half
implemented because the "advertising" field has the implementation.

this patch just adds it for supported reporting.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
---

 ethtool.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index 6c7a2e3..888be57 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -725,6 +725,13 @@ static void dump_supported(struct ethtool_cmd *ep)
 	if (mask & SUPPORTED_2500baseX_Full) {
 		did1++; fprintf(stdout, "2500baseX/Full ");
 	}
+	if (did1 && (mask & SUPPORTED_10000baseT_Full)) {
+		fprintf(stdout, "\n");
+		fprintf(stdout, "	                        ");
+	}
+	if (mask & SUPPORTED_10000baseT_Full) {
+		did1++; fprintf(stdout, "10000baseT/Full ");
+	}
 	fprintf(stdout, "\n");
 
 	fprintf(stdout, "	Supports auto-negotiation: ");

^ permalink raw reply related

* Re: [PATCH][PACKET] Remove unneeded packet_socks_nr variable
From: Arnaldo Carvalho de Melo @ 2007-11-07 16:26 UTC (permalink / raw)
  To: Pavel Emelyanov
  Cc: Arnaldo Carvalho de Melo, David Miller, Linux Netdev List, devel
In-Reply-To: <4731E4CE.6030603@openvz.org>

Em Wed, Nov 07, 2007 at 07:16:14PM +0300, Pavel Emelyanov escreveu:
> Arnaldo Carvalho de Melo wrote:
> > Em Wed, Nov 07, 2007 at 01:50:04PM -0200, Arnaldo Carvalho de Melo escreveu:
> >> Em Wed, Nov 07, 2007 at 06:32:51PM +0300, Pavel Emelyanov escreveu:
> >>> This one is used only under ifdef PACKET_REFCNT_DEBUG in
> >>> printk and is not needed otherwise. So hide all this stuff
> >>> under the PACKET_REFCNT_DEBUG.
> >>>
> >>> Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
> >> Look at sk_refcnt_debug_inc, etc and you'll se a more standard way. I
> >> forgot to make this when making all protocol families use sk_prot, even
> >> if just partially :-)
> > 
> > As a bonus you'll get this information on /proc/net/protocols, removing
> > '-1' from PACKET column for "sockets".
> 
> Hm... I actually thought about this, but I decided that packet
> sockets were not accounted in this way deliberately.
> 
> So, shall I break this "compatibility" (-1 in proc) and provide
> a packet socket number in this file?

Humm, my bad, the sockets column in /proc/net/protocols doesn't come
from prot->socks, it comes from prot->sockets_allocated. But the
suggestion for using sk_refcnt_debug_inc stands, it is there for when we
want to do what the code in pf_packet does: refcount debugging, in fact
that code most probably was copy'n'pasted from other, older protocols.

BTW, IPX also uses this technique, patches are welcome to make it also
use common infrastructure :-)

- Arnaldo

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox