Netdev List
 help / color / mirror / Atom feed
* Re: [patch net-next-2.6] bonding: remove skb_share_check in handle_frame
From: Andy Gospodarek @ 2011-03-01 20:38 UTC (permalink / raw)
  To: Jiri Pirko; +Cc: netdev, davem, fubar, eric.dumazet, nicolas.2p.debian, andy
In-Reply-To: <20110301092907.GG2855@psychotron.redhat.com>

On Tue, Mar 01, 2011 at 10:29:07AM +0100, Jiri Pirko wrote:
> Unapplicable, sorry (wrong branch :(). Here's corrected patch:
> 
> Subject: [PATCH net-next-2.6 v2] bonding: remove skb_share_check in handle_frame
> 
> No need to do share check here.
> 
> Signed-off-by: Jiri Pirko <jpirko@redhat.com>
> ---
>  drivers/net/bonding/bond_main.c |    3 ---
>  1 files changed, 0 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> index 584f97b..367ea60 100644
> --- a/drivers/net/bonding/bond_main.c
> +++ b/drivers/net/bonding/bond_main.c
> @@ -1498,9 +1498,6 @@ static struct sk_buff *bond_handle_frame(struct sk_buff *skb)
>  	struct net_device *slave_dev;
>  	struct net_device *bond_dev;
>  
> -	skb = skb_share_check(skb, GFP_ATOMIC);
> -	if (unlikely(!skb))
> -		return NULL;
>  	slave_dev = skb->dev;
>  	bond_dev = ACCESS_ONCE(slave_dev->master);
>  	if (unlikely(!bond_dev))
> -- 
> 1.7.3.4
> 

Why did you decide to get rid of it here rather than the 3 places in the
bonding driver where it is currently needed?  I think this can cover
those cases since bond_handle_frame will be called after the ptype_all
handlers before any of the ptype handlers.

^ permalink raw reply

* Re: pull request: wireless-2.6 2011-03-01
From: David Miller @ 2011-03-01 20:39 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <20110301184609.GA2536@tuxdriver.com>

From: "John W. Linville" <linville@tuxdriver.com>
Date: Tue, 1 Mar 2011 13:46:10 -0500

> Here is another handful of fixes intended for 2.6.38.  Included are a
> couple of device IDs, a one-liner to allow iwlagn to load a bug-fixed
> firmware for iwl5000, an endian fix for ath9k, another ath9k fix to
> correct a regression involving interrupt enabling, and a fix to disable
> power save mode for BCM4320b in rndis_wlan.
> 
> Please let me know if there are problems!

Pulled, thanks John.

^ permalink raw reply

* Re: [PATCH (sh-2.6) 1/4] clksource: Generic timer infrastructure
From: Arnd Bergmann @ 2011-03-01 20:41 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Stuart Menefy, Peppe CAVALLARO, linux-sh@vger.kernel.org,
	netdev@vger.kernel.org, John Stultz, Thomas Gleixner,
	linux-kernel@vger.kernel.org
In-Reply-To: <20110301202611.GC27107@n2100.arm.linux.org.uk>

On Tuesday 01 March 2011 21:26:11 Russell King - ARM Linux wrote:
> On Tue, Mar 01, 2011 at 05:43:19PM +0100, Arnd Bergmann wrote:
> > On Tuesday 01 March 2011, Stuart Menefy wrote:
> > > On 24/02/11 17:20, Arnd Bergmann wrote:
> > > > Also, what is the difference between this and clkdev?
> > > 
> > > clkdev can be used to find a struct clk, which is fine if you just want to
> > > read the time. In this instance we want to get interrupts from the timer
> > > hardware, which isn't supported by the clk infrastructure.
> > 
> > (adding Russell to Cc)
> > 
> > Is this something that could sensibly be added to clk/clkdev?
> 
> I don't understand - why would anyone want to use clk/clkdev for timers.
> clk/clkdev is all about those signals on the SoC which wiggle at regular
> intervals between logic 0 and logic 1.  It's not about things which count,
> which seems to be an entirely separate problem, and hence why there's
> nothing to deal with interrupts or setting timeouts etc.

Ok, I see. I had mixed the two concepts. The clkdev infrastructure
seemed like a nice way to connect a source and a consumer of a timer,
but you're right that it's an entirely separate thing, and as Thomas
said, it's probably not needed either.

	Arnd

^ permalink raw reply

* Re: [PATCH net-next-2.6] sfc: Reduce size of efx_rx_buffer by unionising skb and page
From: Ben Hutchings @ 2011-03-01 20:47 UTC (permalink / raw)
  To: David Miller; +Cc: linux-net-drivers, netdev
In-Reply-To: <20110301.122459.183051942.davem@davemloft.net>

On Tue, 2011-03-01 at 12:24 -0800, David Miller wrote:
> From: Ben Hutchings <bhutchings@solarflare.com>
> Date: Tue, 01 Mar 2011 01:21:30 +0000
> 
> > From: Steve Hodgson <shodgson@solarflare.com>
> > 
> > [bwh: Forward-ported to net-next-2.6.]
> > Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
> 
> I'm going to apply this, but you can take this further by making
> the buffer an "unsigned long" and encode the pointer plus a one-bit
> binary state there to indicate what it is.

We were primarily concerned with reducing the size of the software ring
for RX queues on 64-bit (DMA address & pointer) systems, where the
structure layout is:

Original:

struct efx_rx_buffer {
       dma_addr_t dma_addr;		// 0
       struct sk_buff *skb;		// 8
       struct page *page;		// 16
       char *data;			// 24
       unsigned int len;		// 32
};					// size = 40

Current:

struct efx_rx_buffer {
       dma_addr_t dma_addr;		// 0
       union {
               struct sk_buff *skb;	// 8
               struct page *page;	// 8
       } u;
       unsigned int len;		// 16
       bool is_page;			// 20
};					// size = 24

Combining the flag with the pointers wouldn't improve on this:

struct efx_rx_buffer {
       dma_addr_t dma_addr;		// 0
       unsigned long magic_pointer;	// 8
       unsigned int len;		// 16
};					// size = 24

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply

* Re: [PATCH net-next-2.6] sfc: Reduce size of efx_rx_buffer by unionising skb and page
From: David Miller @ 2011-03-01 21:08 UTC (permalink / raw)
  To: bhutchings; +Cc: linux-net-drivers, netdev
In-Reply-To: <1299012424.2529.39.camel@bwh-desktop>

From: Ben Hutchings <bhutchings@solarflare.com>
Date: Tue, 01 Mar 2011 20:47:04 +0000

> Combining the flag with the pointers wouldn't improve on this:

Good point, but:

1) One less load in your RX fast path.

2) 32-bits of space for any addition state you might like to add later

^ permalink raw reply

* Re: [PATCH] ipv6: Consolidate route lookup sequences.
From: David Miller @ 2011-03-01 21:20 UTC (permalink / raw)
  To: netdev
In-Reply-To: <20110301.123640.59675298.davem@davemloft.net>

From: David Miller <davem@davemloft.net>
Date: Tue, 01 Mar 2011 12:36:40 -0800 (PST)

> 
> Route lookups follow a general pattern in the ipv6 code wherein
> we first find the non-IPSEC route, potentially override the
> flow destination address due to ipv6 options settings, and then
> finally make an IPSEC search using either xfrm_lookup() or
> __xfrm_lookup().
 ...

While self-auditing this patch noticied I missed a few dccp and
inet6 connection sock cases.  This patch should be better:

--------------------
ipv6: Consolidate route lookup sequences.

Route lookups follow a general pattern in the ipv6 code wherein
we first find the non-IPSEC route, potentially override the
flow destination address due to ipv6 options settings, and then
finally make an IPSEC search using either xfrm_lookup() or
__xfrm_lookup().

__xfrm_lookup() is used when we want to generate a blackhole route
if the key manager needs to resolve the IPSEC rules (in this case
-EREMOTE is returned and the original 'dst' is left unchanged).

Otherwise plain xfrm_lookup() is used and when asynchronous IPSEC
resolution is necessary, we simply fail the lookup completely.

All of these cases are encapsulated into two routines,
ip6_dst_lookup_flow and ip6_sk_dst_lookup_flow.  The latter of which
handles unconnected UDP datagram sockets.

Signed-off-by: David S. Miller <davem@davemloft.net>
---
 include/net/ipv6.h               |   11 ++++-
 net/dccp/ipv6.c                  |   65 +++++++++---------------------
 net/ipv6/af_inet6.c              |   17 ++------
 net/ipv6/datagram.c              |   15 ++-----
 net/ipv6/inet6_connection_sock.c |   25 +++---------
 net/ipv6/ip6_output.c            |   80 ++++++++++++++++++++++++++++++++-----
 net/ipv6/raw.c                   |   15 +------
 net/ipv6/syncookies.c            |    7 +--
 net/ipv6/tcp_ipv6.c              |   57 ++++++++++-----------------
 net/ipv6/udp.c                   |   15 ++-----
 10 files changed, 142 insertions(+), 165 deletions(-)

diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 4a3cd2c..1fc5631 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -512,12 +512,17 @@ extern void			ip6_flush_pending_frames(struct sock *sk);
 extern int			ip6_dst_lookup(struct sock *sk,
 					       struct dst_entry **dst,
 					       struct flowi *fl);
+extern struct dst_entry *	ip6_dst_lookup_flow(struct sock *sk,
+						    struct flowi *fl,
+						    const struct in6_addr *final_dst,
+						    bool want_blackhole);
+extern struct dst_entry *	ip6_sk_dst_lookup_flow(struct sock *sk,
+						       struct flowi *fl,
+						       const struct in6_addr *final_dst,
+						       bool want_blackhole);
 extern int			ip6_dst_blackhole(struct sock *sk,
 						  struct dst_entry **dst,
 						  struct flowi *fl);
-extern int			ip6_sk_dst_lookup(struct sock *sk,
-						  struct dst_entry **dst,
-						  struct flowi *fl);
 
 /*
  *	skb processing functions
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 460d545..5efc57f 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -162,15 +162,9 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 			fl.fl_ip_sport = inet->inet_sport;
 			security_sk_classify_flow(sk, &fl);
 
-			err = ip6_dst_lookup(sk, &dst, &fl);
-			if (err) {
-				sk->sk_err_soft = -err;
-				goto out;
-			}
-
-			err = xfrm_lookup(net, &dst, &fl, sk, 0);
-			if (err < 0) {
-				sk->sk_err_soft = -err;
+			dst = ip6_dst_lookup_flow(sk, &fl, NULL, false);
+			if (IS_ERR(dst)) {
+				sk->sk_err_soft = -PTR_ERR(dst);
 				goto out;
 			}
 		} else
@@ -267,16 +261,12 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
 
 	final_p = fl6_update_dst(&fl, opt, &final);
 
-	err = ip6_dst_lookup(sk, &dst, &fl);
-	if (err)
-		goto done;
-
-	if (final_p)
-		ipv6_addr_copy(&fl.fl6_dst, final_p);
-
-	err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0);
-	if (err < 0)
+	dst = ip6_dst_lookup_flow(sk, &fl, final_p, false);
+	if (IS_ERR(dst)) {
+		err = PTR_ERR(dst);
+		dst = NULL;
 		goto done;
+	}
 
 	skb = dccp_make_response(sk, dst, req);
 	if (skb != NULL) {
@@ -338,14 +328,13 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
 	security_skb_classify_flow(rxskb, &fl);
 
 	/* sk = NULL, but it is safe for now. RST socket required. */
-	if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) {
-		if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) {
-			skb_dst_set(skb, dst);
-			ip6_xmit(ctl_sk, skb, &fl, NULL);
-			DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
-			DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
-			return;
-		}
+	dst = ip6_dst_lookup_flow(ctl_sk, &fl, NULL, false);
+	if (!IS_ERR(dst)) {
+		skb_dst_set(skb, dst);
+		ip6_xmit(ctl_sk, skb, &fl, NULL);
+		DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
+		DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
+		return;
 	}
 
 	kfree_skb(skb);
@@ -550,13 +539,8 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
 		fl.fl_ip_sport = inet_rsk(req)->loc_port;
 		security_sk_classify_flow(sk, &fl);
 
-		if (ip6_dst_lookup(sk, &dst, &fl))
-			goto out;
-
-		if (final_p)
-			ipv6_addr_copy(&fl.fl6_dst, final_p);
-
-		if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
+		dst = ip6_dst_lookup_flow(sk, &fl, final_p, false);
+		if (IS_ERR(dst))
 			goto out;
 	}
 
@@ -979,19 +963,10 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 
 	final_p = fl6_update_dst(&fl, np->opt, &final);
 
-	err = ip6_dst_lookup(sk, &dst, &fl);
-	if (err)
+	dst = ip6_dst_lookup_flow(sk, &fl, final_p, true);
+	if (IS_ERR(dst)) {
+		err = PTR_ERR(dst);
 		goto failure;
-
-	if (final_p)
-		ipv6_addr_copy(&fl.fl6_dst, final_p);
-
-	err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
-	if (err < 0) {
-		if (err == -EREMOTE)
-			err = ip6_dst_blackhole(sk, &dst, &fl);
-		if (err < 0)
-			goto failure;
 	}
 
 	if (saddr == NULL) {
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 3194aa9..a88b2e9 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -644,9 +644,8 @@ EXPORT_SYMBOL(inet6_unregister_protosw);
 
 int inet6_sk_rebuild_header(struct sock *sk)
 {
-	int err;
-	struct dst_entry *dst;
 	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct dst_entry *dst;
 
 	dst = __sk_dst_check(sk, np->dst_cookie);
 
@@ -668,17 +667,11 @@ int inet6_sk_rebuild_header(struct sock *sk)
 
 		final_p = fl6_update_dst(&fl, np->opt, &final);
 
-		err = ip6_dst_lookup(sk, &dst, &fl);
-		if (err) {
+		dst = ip6_dst_lookup_flow(sk, &fl, final_p, false);
+		if (IS_ERR(dst)) {
 			sk->sk_route_caps = 0;
-			return err;
-		}
-		if (final_p)
-			ipv6_addr_copy(&fl.fl6_dst, final_p);
-
-		if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) {
-			sk->sk_err_soft = -err;
-			return err;
+			sk->sk_err_soft = -PTR_ERR(dst);
+			return PTR_ERR(dst);
 		}
 
 		__ip6_dst_store(sk, dst, NULL, NULL);
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 320bdb8..be3a781 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -162,18 +162,11 @@ ipv4_connected:
 	opt = flowlabel ? flowlabel->opt : np->opt;
 	final_p = fl6_update_dst(&fl, opt, &final);
 
-	err = ip6_dst_lookup(sk, &dst, &fl);
-	if (err)
+	dst = ip6_dst_lookup_flow(sk, &fl, final_p, true);
+	err = 0;
+	if (IS_ERR(dst)) {
+		err = PTR_ERR(dst);
 		goto out;
-	if (final_p)
-		ipv6_addr_copy(&fl.fl6_dst, final_p);
-
-	err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
-	if (err < 0) {
-		if (err == -EREMOTE)
-			err = ip6_dst_blackhole(sk, &dst, &fl);
-		if (err < 0)
-			goto out;
 	}
 
 	/* source address lookup done in ip6_dst_lookup */
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index d144e62..d687e13 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -74,13 +74,8 @@ struct dst_entry *inet6_csk_route_req(struct sock *sk,
 	fl.fl_ip_sport = inet_rsk(req)->loc_port;
 	security_req_classify_flow(req, &fl);
 
-	if (ip6_dst_lookup(sk, &dst, &fl))
-		return NULL;
-
-	if (final_p)
-		ipv6_addr_copy(&fl.fl6_dst, final_p);
-
-	if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
+	dst = ip6_dst_lookup_flow(sk, &fl, final_p, false);
+	if (IS_ERR(dst))
 		return NULL;
 
 	return dst;
@@ -234,21 +229,13 @@ int inet6_csk_xmit(struct sk_buff *skb)
 	dst = __inet6_csk_dst_check(sk, np->dst_cookie);
 
 	if (dst == NULL) {
-		int err = ip6_dst_lookup(sk, &dst, &fl);
-
-		if (err) {
-			sk->sk_err_soft = -err;
-			kfree_skb(skb);
-			return err;
-		}
-
-		if (final_p)
-			ipv6_addr_copy(&fl.fl6_dst, final_p);
+		dst = ip6_dst_lookup_flow(sk, &fl, final_p, false);
 
-		if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) {
+		if (IS_ERR(dst)) {
+			sk->sk_err_soft = -PTR_ERR(dst);
 			sk->sk_route_caps = 0;
 			kfree_skb(skb);
-			return err;
+			return PTR_ERR(dst);
 		}
 
 		__inet6_csk_dst_store(sk, dst, NULL, NULL);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 5c618f2..28209b2 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1002,29 +1002,87 @@ int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl)
 EXPORT_SYMBOL_GPL(ip6_dst_lookup);
 
 /**
- *	ip6_sk_dst_lookup - perform socket cached route lookup on flow
+ *	ip6_dst_lookup_flow - perform route lookup on flow with ipsec
+ *	@sk: socket which provides route info
+ *	@fl: flow to lookup
+ *	@final_dst: final destination address for ipsec lookup
+ *	@want_blackhole: IPSEC blackhole handling desired
+ *
+ *	This function performs a route lookup on the given flow.
+ *
+ *	It returns a valid dst pointer on success, or a pointer encoded
+ *	error code.
+ */
+struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi *fl,
+				      const struct in6_addr *final_dst,
+				      bool want_blackhole)
+{
+	struct dst_entry *dst = NULL;
+	int err;
+
+	err = ip6_dst_lookup_tail(sk, &dst, fl);
+	if (err)
+		return ERR_PTR(err);
+	if (final_dst)
+		ipv6_addr_copy(&fl->fl6_dst, final_dst);
+	if (want_blackhole) {
+		err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, XFRM_LOOKUP_WAIT);
+		if (err == -EREMOTE)
+			err = ip6_dst_blackhole(sk, &dst, fl);
+		if (err)
+			return ERR_PTR(err);
+	} else {
+		err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
+		if (err)
+			return ERR_PTR(err);
+	}
+	return dst;
+}
+EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow);
+
+/**
+ *	ip6_sk_dst_lookup_flow - perform socket cached route lookup on flow
  *	@sk: socket which provides the dst cache and route info
- *	@dst: pointer to dst_entry * for result
  *	@fl: flow to lookup
+ *	@final_dst: final destination address for ipsec lookup
+ *	@want_blackhole: IPSEC blackhole handling desired
  *
  *	This function performs a route lookup on the given flow with the
  *	possibility of using the cached route in the socket if it is valid.
  *	It will take the socket dst lock when operating on the dst cache.
  *	As a result, this function can only be used in process context.
  *
- *	It returns zero on success, or a standard errno code on error.
+ *	It returns a valid dst pointer on success, or a pointer encoded
+ *	error code.
  */
-int ip6_sk_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl)
+struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi *fl,
+					 const struct in6_addr *final_dst,
+					 bool want_blackhole)
 {
-	*dst = NULL;
-	if (sk) {
-		*dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie);
-		*dst = ip6_sk_dst_check(sk, *dst, fl);
-	}
+	struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie);
+	int err;
 
-	return ip6_dst_lookup_tail(sk, dst, fl);
+	dst = ip6_sk_dst_check(sk, dst, fl);
+
+	err = ip6_dst_lookup_tail(sk, &dst, fl);
+	if (err)
+		return ERR_PTR(err);
+	if (final_dst)
+		ipv6_addr_copy(&fl->fl6_dst, final_dst);
+	if (want_blackhole) {
+		err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, XFRM_LOOKUP_WAIT);
+		if (err == -EREMOTE)
+			err = ip6_dst_blackhole(sk, &dst, fl);
+		if (err)
+			return ERR_PTR(err);
+	} else {
+		err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
+		if (err)
+			return ERR_PTR(err);
+	}
+	return dst;
 }
-EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup);
+EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
 
 static inline int ip6_ufo_append_data(struct sock *sk,
 			int getfrag(void *from, char *to, int offset, int len,
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 364e866..dc29b07 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -856,20 +856,11 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
 		fl.oif = np->mcast_oif;
 	security_sk_classify_flow(sk, &fl);
 
-	err = ip6_dst_lookup(sk, &dst, &fl);
-	if (err)
+	dst = ip6_dst_lookup_flow(sk, &fl, final_p, true);
+	if (IS_ERR(dst)) {
+		err = PTR_ERR(dst);
 		goto out;
-	if (final_p)
-		ipv6_addr_copy(&fl.fl6_dst, final_p);
-
-	err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
-	if (err < 0) {
-		if (err == -EREMOTE)
-			err = ip6_dst_blackhole(sk, &dst, &fl);
-		if (err < 0)
-			goto out;
 	}
-
 	if (hlimit < 0) {
 		if (ipv6_addr_is_multicast(&fl.fl6_dst))
 			hlimit = np->mcast_hops;
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 09fd34f..0b4cf35 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -243,12 +243,9 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
 		fl.fl_ip_dport = inet_rsk(req)->rmt_port;
 		fl.fl_ip_sport = inet_sk(sk)->inet_sport;
 		security_req_classify_flow(req, &fl);
-		if (ip6_dst_lookup(sk, &dst, &fl))
-			goto out_free;
 
-		if (final_p)
-			ipv6_addr_copy(&fl.fl6_dst, final_p);
-		if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
+		dst = ip6_dst_lookup_flow(sk, &fl, final_p, false);
+		if (IS_ERR(dst))
 			goto out_free;
 	}
 
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 1d0ab55..e59a31c 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -255,18 +255,10 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 
 	security_sk_classify_flow(sk, &fl);
 
-	err = ip6_dst_lookup(sk, &dst, &fl);
-	if (err)
+	dst = ip6_dst_lookup_flow(sk, &fl, final_p, true);
+	if (IS_ERR(dst)) {
+		err = PTR_ERR(dst);
 		goto failure;
-	if (final_p)
-		ipv6_addr_copy(&fl.fl6_dst, final_p);
-
-	err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
-	if (err < 0) {
-		if (err == -EREMOTE)
-			err = ip6_dst_blackhole(sk, &dst, &fl);
-		if (err < 0)
-			goto failure;
 	}
 
 	if (saddr == NULL) {
@@ -385,7 +377,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 	np = inet6_sk(sk);
 
 	if (type == ICMPV6_PKT_TOOBIG) {
-		struct dst_entry *dst = NULL;
+		struct dst_entry *dst;
 
 		if (sock_owned_by_user(sk))
 			goto out;
@@ -413,13 +405,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 			fl.fl_ip_sport = inet->inet_sport;
 			security_skb_classify_flow(skb, &fl);
 
-			if ((err = ip6_dst_lookup(sk, &dst, &fl))) {
-				sk->sk_err_soft = -err;
-				goto out;
-			}
-
-			if ((err = xfrm_lookup(net, &dst, &fl, sk, 0)) < 0) {
-				sk->sk_err_soft = -err;
+			dst = ip6_dst_lookup_flow(sk, &fl, NULL, false);
+			if (IS_ERR(dst)) {
+				sk->sk_err_soft = -PTR_ERR(dst);
 				goto out;
 			}
 
@@ -496,7 +484,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
 	struct in6_addr * final_p, final;
 	struct flowi fl;
 	struct dst_entry *dst;
-	int err = -1;
+	int err;
 
 	memset(&fl, 0, sizeof(fl));
 	fl.proto = IPPROTO_TCP;
@@ -512,15 +500,13 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
 	opt = np->opt;
 	final_p = fl6_update_dst(&fl, opt, &final);
 
-	err = ip6_dst_lookup(sk, &dst, &fl);
-	if (err)
+	dst = ip6_dst_lookup_flow(sk, &fl, final_p, false);
+	if (IS_ERR(dst)) {
+		err = PTR_ERR(dst);
 		goto done;
-	if (final_p)
-		ipv6_addr_copy(&fl.fl6_dst, final_p);
-	if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
-		goto done;
-
+	}
 	skb = tcp_make_synack(sk, dst, req, rvp);
+	err = -ENOMEM;
 	if (skb) {
 		__tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr);
 
@@ -1079,15 +1065,14 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
 	 * Underlying function will use this to retrieve the network
 	 * namespace
 	 */
-	if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) {
-		if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) {
-			skb_dst_set(buff, dst);
-			ip6_xmit(ctl_sk, buff, &fl, NULL);
-			TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
-			if (rst)
-				TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
-			return;
-		}
+	dst = ip6_dst_lookup_flow(ctl_sk, &fl, NULL, false);
+	if (!IS_ERR(dst)) {
+		skb_dst_set(buff, dst);
+		ip6_xmit(ctl_sk, buff, &fl, NULL);
+		TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
+		if (rst)
+			TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
+		return;
 	}
 
 	kfree_skb(buff);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index a419a78..d86d7f6 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1125,18 +1125,11 @@ do_udp_sendmsg:
 
 	security_sk_classify_flow(sk, &fl);
 
-	err = ip6_sk_dst_lookup(sk, &dst, &fl);
-	if (err)
+	dst = ip6_sk_dst_lookup_flow(sk, &fl, final_p, true);
+	if (IS_ERR(dst)) {
+		err = PTR_ERR(dst);
+		dst = NULL;
 		goto out;
-	if (final_p)
-		ipv6_addr_copy(&fl.fl6_dst, final_p);
-
-	err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
-	if (err < 0) {
-		if (err == -EREMOTE)
-			err = ip6_dst_blackhole(sk, &dst, &fl);
-		if (err < 0)
-			goto out;
 	}
 
 	if (hlimit < 0) {
-- 
1.7.4.1



^ permalink raw reply related

* Re: [PATCH net-2.6] bonding: drop frames received with master's source MAC
From: Nicolas de Pesloüan @ 2011-03-01 21:30 UTC (permalink / raw)
  To: Andy Gospodarek
  Cc: Jay Vosburgh, netdev, David Miller, Herbert Xu, Jiri Pirko
In-Reply-To: <20110301181624.GM11864@gospo.rdu.redhat.com>

Le 01/03/2011 19:16, Andy Gospodarek a écrit :

[snip]

> Knowing that I'm using an unmanaged switch with balance-rr probably
> helps understand how this is happening.  I'll clarify this however, so
> we are all on the same page.
>
> In my situation, eth2 and eth3 are in bond0.  When bond0 transmits the
> NS, let's say it goes out eth3.  Since it is a multicast frame my switch
> will broadcast this to all ports and eth2 will receive the frame with
> the source MAC address being the same as bond0's MAC address.  This
> frame is passed up the stack to the ipv6 layer and appears to be a
> response to the NS from another host and is dropped.

'sounds perfectly normal.

This problem is described in detail in chapter 5.4.3 and appendix A of RFC4862 "IPv6 Stateless 
Address Autoconfiguration".

As this is clearly IPv6 related, it sounds normal from my point of view to fix it at the 
ndisc_recv_ns() level.

Quoting the RFC:

   "In those cases where the hardware cannot suppress loopbacks, however,
    one possible software heuristic to filter out unwanted loopbacks is
    to discard any received packet whose link-layer source address is the
    same as the receiving interface's.  There is even a link-layer
    specification that requires that any such packets be discarded
    [IEEE802.11].  Unfortunately, use of that criteria also results in
    the discarding of all packets sent by another node using the same
    link-layer address.  Duplicate Address Detection will fail on
    interfaces that filter received packets in this manner:

    [snip]

    Thus, to perform Duplicate Address Detection correctly in the case
    where two interfaces are using the same link-layer address, an
    implementation must have a good understanding of the interface's
    multicast loopback semantics, and the interface cannot discard
    received packets simply because the source link-layer address is the
    same as the interface's."

So, simply dropping frames whose source MAC == local MAC is apparently not the right solution.

	Nicolas.

^ permalink raw reply

* [PATCH v2] net: don't allow CAP_NET_ADMIN to load non-netdev kernel modules
From: Vasiliy Kulikov @ 2011-03-01 21:33 UTC (permalink / raw)
  To: linux-kernel
  Cc: mjt, arnd, mirqus, netdev, Ben Hutchings, David Miller, kuznet,
	pekkas, jmorris, yoshfuji, kaber, eric.dumazet, therbert, xiaosuo,
	jesse, kees.cook, eugene, dan.j.rosenberg, akpm
In-Reply-To: <1299010390.2529.30.camel@bwh-desktop>

Since a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565c any process with
CAP_NET_ADMIN may load any module from /lib/modules/.  This doesn't mean
that CAP_NET_ADMIN is a superset of CAP_SYS_MODULE as modules are
limited to /lib/modules/**.  However, CAP_NET_ADMIN capability shouldn't
allow anybody load any module not related to networking.

This patch restricts an ability of autoloading modules to netdev modules
with explicit aliases.  This fixes CVE-2011-1019.

Arnd Bergmann suggested to leave untouched the old pre-v2.6.32 behavior
of loading netdev modules by name (without any prefix) for processes
with CAP_SYS_MODULE to maintain the compatibility with network scripts
that use autoloading netdev modules by aliases like "eth0", "wlan0".

Currently there are only three users of the feature in the upstream
kernel: ipip, ip_gre and sit.

    root@albatros:~# capsh --drop=$(seq -s, 0 11),$(seq -s, 13 34) --
    root@albatros:~# grep Cap /proc/$$/status
    CapInh:	0000000000000000
    CapPrm:	fffffff800001000
    CapEff:	fffffff800001000
    CapBnd:	fffffff800001000
    root@albatros:~# modprobe xfs
    FATAL: Error inserting xfs
    (/lib/modules/2.6.38-rc6-00001-g2bf4ca3/kernel/fs/xfs/xfs.ko): Operation not permitted
    root@albatros:~# lsmod | grep xfs
    root@albatros:~# ifconfig xfs
    xfs: error fetching interface information: Device not found
    root@albatros:~# lsmod | grep xfs
    root@albatros:~# lsmod | grep sit
    root@albatros:~# ifconfig sit
    sit: error fetching interface information: Device not found
    root@albatros:~# lsmod | grep sit
    root@albatros:~# ifconfig sit0
    sit0      Link encap:IPv6-in-IPv4
	      NOARP  MTU:1480  Metric:1

    root@albatros:~# lsmod | grep sit
    sit                    10457  0
    tunnel4                 2957  1 sit

For CAP_SYS_MODULE module loading is still relaxed:

    root@albatros:~# grep Cap /proc/$$/status
    CapInh:	0000000000000000
    CapPrm:	ffffffffffffffff
    CapEff:	ffffffffffffffff
    CapBnd:	ffffffffffffffff
    root@albatros:~# ifconfig xfs
    xfs: error fetching interface information: Device not found
    root@albatros:~# lsmod | grep xfs
    xfs                   745319  0

Reference: https://lkml.org/lkml/2011/2/24/203

Signed-off-by: Vasiliy Kulikov <segoon@openwall.com>
---
 v2 - use pr_err()
    - don't try to load $name if netdev-$name is loaded

 include/linux/netdevice.h |    3 +++
 net/core/dev.c            |   12 ++++++++++--
 net/ipv4/ip_gre.c         |    2 +-
 net/ipv4/ipip.c           |    2 +-
 net/ipv6/sit.c            |    2 +-
 5 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index d971346..71caf7a 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2392,6 +2392,9 @@ extern int netdev_notice(const struct net_device *dev, const char *format, ...)
 extern int netdev_info(const struct net_device *dev, const char *format, ...)
 	__attribute__ ((format (printf, 2, 3)));
 
+#define MODULE_ALIAS_NETDEV(device) \
+	MODULE_ALIAS("netdev-" device)
+
 #if defined(DEBUG)
 #define netdev_dbg(__dev, format, args...)			\
 	netdev_printk(KERN_DEBUG, __dev, format, ##args)
diff --git a/net/core/dev.c b/net/core/dev.c
index 8ae6631..6561021 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1114,13 +1114,21 @@ EXPORT_SYMBOL(netdev_bonding_change);
 void dev_load(struct net *net, const char *name)
 {
 	struct net_device *dev;
+	int no_module;
 
 	rcu_read_lock();
 	dev = dev_get_by_name_rcu(net, name);
 	rcu_read_unlock();
 
-	if (!dev && capable(CAP_NET_ADMIN))
-		request_module("%s", name);
+	no_module = !dev;
+	if (no_module && capable(CAP_NET_ADMIN))
+		no_module = request_module("netdev-%s", name);
+	if (no_module && capable(CAP_SYS_MODULE)) {
+		if (!request_module("%s", name))
+			pr_err("Loading kernel module for a network device "
+"with CAP_SYS_MODULE (deprecated).  Use CAP_NET_ADMIN and alias netdev-%s "
+"instead\n", name);
+	}
 }
 EXPORT_SYMBOL(dev_load);
 
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 6613edf..d1d0e2c 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -1765,4 +1765,4 @@ module_exit(ipgre_fini);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_RTNL_LINK("gre");
 MODULE_ALIAS_RTNL_LINK("gretap");
-MODULE_ALIAS("gre0");
+MODULE_ALIAS_NETDEV("gre0");
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 988f52f..a5f58e7 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -913,4 +913,4 @@ static void __exit ipip_fini(void)
 module_init(ipip_init);
 module_exit(ipip_fini);
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("tunl0");
+MODULE_ALIAS_NETDEV("tunl0");
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 8ce38f1..d2c16e1 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -1290,4 +1290,4 @@ static int __init sit_init(void)
 module_init(sit_init);
 module_exit(sit_cleanup);
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("sit0");
+MODULE_ALIAS_NETDEV("sit0");
-- 
1.7.0.4

^ permalink raw reply related

* Re: 2.6.37 regression: adding main interface to a bridge breaks vlan interface RX
From: Francois Romieu @ 2011-03-01 21:52 UTC (permalink / raw)
  To: Jesse Gross; +Cc: chriss, netdev
In-Reply-To: <20110301101609.GA13261@electric-eye.fr.zoreil.com>

Francois Romieu <romieu@fr.zoreil.com> :
> Jesse Gross <jesse@nicira.com> :
> [...]
> > Regardless, the solution is to remove the dependency on vlan devices
> > by converting over to the new vlan model.  Francois, any chance that
> > you might have some time to look at this?
> 
> The completely untested patch below is available for the (really) desperate
> souls.
> 
> I should do a -next testing session this afternoon for this patch + 
> Oliver's Neukum advertisement control + Hayes 8105e stuff (in reverse order).

It took a bit longer than expected but the patch seems to work.

Chriss, can you give it a try against current -rc / -git and see if it makes
a difference ?

-- 
Ueimor

^ permalink raw reply

* Re: [PATCH net-2.6] bonding: drop frames received with master's source MAC
From: Jay Vosburgh @ 2011-03-01 22:25 UTC (permalink / raw)
  To: =?ISO-8859-1?Q?Nicolas_de_Peslo=FCan?=
  Cc: Andy Gospodarek, netdev, David Miller, Herbert Xu, Jiri Pirko
In-Reply-To: <4D6D658C.90300@gmail.com>

Nicolas de Pesloüan 	<nicolas.2p.debian@gmail.com> wrote:

>Le 01/03/2011 19:16, Andy Gospodarek a écrit :
>
>[snip]
>
>> Knowing that I'm using an unmanaged switch with balance-rr probably
>> helps understand how this is happening.  I'll clarify this however, so
>> we are all on the same page.
>>
>> In my situation, eth2 and eth3 are in bond0.  When bond0 transmits the
>> NS, let's say it goes out eth3.  Since it is a multicast frame my switch
>> will broadcast this to all ports and eth2 will receive the frame with
>> the source MAC address being the same as bond0's MAC address.  This
>> frame is passed up the stack to the ipv6 layer and appears to be a
>> response to the NS from another host and is dropped.
>
>'sounds perfectly normal.
>
>This problem is described in detail in chapter 5.4.3 and appendix A of
>RFC4862 "IPv6 Stateless Address Autoconfiguration".
>
>As this is clearly IPv6 related, it sounds normal from my point of view to
>fix it at the ndisc_recv_ns() level.

	Andy's immediate problem is IPv6 related, but the issue itself
is generic: how to deal with broadcast / multicasts arriving at a -rr or
-xor bond, because we do not and cannot know if the switch is going to
flood to the slaves or not.  There may be other instances wherein that
bonus copy of some packet confuses things.

	My view is that -rr and -xor are intended to interoperate with
Etherchannel.  Yes, they will often work tolerably well when connected
to a non-Etherchannel switch.  But, if the host and the switch are not
in agreement on the link aggregation status of the ports, some level of
misbehavior is expected.  If that misbehavior can be corrected without
adversely affecting a properly configured host and switch, then I don't
see much problem with fixing it.

	For the IPv6 case here, I think there's a problem with any fix,
and that is that there's no way for bonding to know if the switch ports
are configured properly or not.  I'm using "properly" to mean that the
switch ports corresponding to the bonding slaves are configured into an
Etherchannel-type channel group.

	If the switch ports are grouped, then if IPv6 sees one of these
messages coming in, it's actually a duplicate detection.  This because
the switch won't loop the broadcast / multicast back around to a member
of the channel group.

	If the switch ports are not grouped, then the switch will
happily send broadcasts and multicasts to all ports of the bond, because
it doesn't know about the aggregation.  In this case, I suspect there's
no way to reliably determine if the incoming packet is a switch artifact
or an actual duplicate detection.  Anybody know for sure if this is the
case?

	For the generic case, I'm not seeing a way to distinguish actual
repeated packets from switch artifact duplicate packets without adding
another knob to bonding to tell it if the switch does etherchannel or
not (which I'm not in favor of doing).

>Quoting the RFC:
>
>  "In those cases where the hardware cannot suppress loopbacks, however,
>   one possible software heuristic to filter out unwanted loopbacks is
>   to discard any received packet whose link-layer source address is the
>   same as the receiving interface's.  There is even a link-layer
>   specification that requires that any such packets be discarded
>   [IEEE802.11].  Unfortunately, use of that criteria also results in
>   the discarding of all packets sent by another node using the same
>   link-layer address.  Duplicate Address Detection will fail on
>   interfaces that filter received packets in this manner:
>
>   [snip]
>
>   Thus, to perform Duplicate Address Detection correctly in the case
>   where two interfaces are using the same link-layer address, an
>   implementation must have a good understanding of the interface's
>   multicast loopback semantics, and the interface cannot discard
>   received packets simply because the source link-layer address is the
>   same as the interface's."
>
>So, simply dropping frames whose source MAC == local MAC is apparently not the right solution.

	I tend to agree here, because this would break DAD for properly
configured (meaning etherchannel on the switch ports) installations.

	Is there a way to fix bonding and/or ndisc_recv_ns to work
correctly for both cases (have/don't have etherchannel on the switch)?

	-J

---
	-Jay Vosburgh, IBM Linux Technology Center, fubar@us.ibm.com

^ permalink raw reply

* [PATCH] bonding: added 802.3ad round-robin hashing policy and source mac selection mode
From: Oleg V. Ukhno @ 2011-03-01 22:34 UTC (permalink / raw)
  To: netdev; +Cc: Jay Vosburgh, David S. Miller

Patch introduces two new (related) features to bonding module.
First feature is round-robin hashing policy, which is primarily
intended for use with 802.3ad mode, and puts every next IPv4 and
IPv6 packet into  next availables slave without taling into account
which layer3 and above protocol is used.
Second feature makes possible choosing which MAC-address will be set
in the transmitted packet - when set to src-mac it will force setting
slave's interface real MAC address as source MAC address in every
packet, sent via this slave interface.
Main goal of this patch is to make possible single TCP stream
equally striped for both transmitted and received packets over all
available slaves.
This operating mode is not fully 802.3ad compliant, and will cause
some packet reordering in TCP stream, to some kernel tuning may be
required.
For correct working enabling round-robin hashing policy plus using
real slave's MAC addresses as source MAC addresses in transmitted
packets requires specific switch setting)hashing mode for port-channel
("etherchannel) should be set to src-mac or src-dst-mac to get
correct load-striping on the receiving host's etherchannel.
General requirements for using bonding in this operating mode are:
- even and preferrably equal number of slaves on sending and receiving
hosts;
- equal RTT between sending and receiving hosts on all slaves;
- switch capable of doing etherchannels and using src-mac or src-dst-mac
hashing policy for egress load striping

Signed-off-by: Oleg V. Ukhno <olegu@yandex-team.ru>
---
 
Documentation/networking/bonding.txt |  109 +++++++++++++++++++++++++++++++++++
 drivers/net/bonding/bond_3ad.c       |    2 
 drivers/net/bonding/bond_main.c      |   59 +++++++++++++++++-
 drivers/net/bonding/bond_sysfs.c     |   50 ++++++++++++++++
 drivers/net/bonding/bonding.h        |   11 ++-
 include/linux/if_bonding.h           |    1 
 6 files changed, 223 insertions(+), 9 deletions(-)

diff -uprN -X linux-2.6/Documentation/dontdiff linux-2.6/Documentation/networking/bonding.txt linux-2.6.p/Documentation/networking/bonding.txt
--- linux-2.6/Documentation/networking/bonding.txt	2011-02-08 16:03:01.290281998 +0300
+++ linux-2.6.p/Documentation/networking/bonding.txt	2011-03-01 22:27:56.570282000 +0300
@@ -83,6 +83,7 @@ Table of Contents
 12. Configuring Bonding for Maximum Throughput
 12.1	Maximum Throughput in a Single Switch Topology
 12.1.1		MT Bonding Mode Selection for Single Switch Topology
+12.1.1.1 		Maximizing TCP Throughput for RX/TX for Single Switch Topology using layer2 mechanisms
 12.1.2		MT Link Monitoring for Single Switch Topology
 12.2	Maximum Throughput in a Multiple Switch Topology
 12.2.1		MT Bonding Mode Selection for Multiple Switch Topology
@@ -761,11 +762,62 @@ xmit_hash_policy
 		conversations.  Other implementations of 802.3ad may
 		or may not tolerate this noncompliance.
 
+	round-robin
+
+		This policy simply puts every next packet into next
+		slave interfaces, providing round-robin load striping
+		for transmitted data. This policy can be enabled with
+		any mode which supports choosing alternate hash policy,
+		but was initially done for 802.3ad mode.
+
+		Main goal for this policy is to stripe TX load without
+		taking into account which layer3 protocol is used, and
+		can be used for single TCP connection load striping. When
+		enabled, it will round-robin packets for IPv4 and IPv6
+		only.
+
+		There is also src_mac_select option, which can be used
+		to configure RX load-striping using switch hashing
+		algorhytms on the receiving side. See detailed description
+		below.
+
+		This algorithm is not 802.3ad compliant.  This hash
+		policy will generally cause TCP packets to be delivered
+		out of order.  Other implementations of 802.3ad may or
+		may not tolerate this noncompliance.
+
 	The default value is layer2.  This option was added in bonding
 	version 2.6.3.  In earlier versions of bonding, this parameter
 	does not exist, and the layer2 policy is the only policy.  The
 	layer2+3 value was added for bonding version 3.2.2.
 
+src_mac_select
+
+	Specifies the source MAC selection method for outgoing packets.
+
+	Possible values are:
+
+	default or 0
+
+		The normal selection policy for the bonding mode is
+		used.  This varies according to the bonding mode.  The
+		balance-xor, balance-rr, 802.3ad and broadcast modes use
+		the MAC address of the bonding master.  The balance-alb
+		and balance-tlb modes use the MAC address of the slave
+		the packet is sent on.
+
+	slave-src or 1
+
+		Sets the source MAC for all outgoing IPv4 and IPv6
+		packets to the MAC address of the slave the packet is
+		sent on.  This is intended to permit fine grained load
+		balancing for 802.3ad and balance-xor modes by changing
+		the slave's MAC addresses.  This is documented in detail
+		in section 12.1.1.1.
+
+	This option was added for bonding version 3.8.0
+
+
 resend_igmp
 
 	Specifies the number of IGMP membership reports to be issued after
@@ -2190,6 +2242,63 @@ balance-alb: This mode is everything tha
 	device driver must support changing the hardware address while
 	the device is open.
 
+12.1.1.1 Maximizing TCP Throughput for RX/TX for Single Switch Topology
+         using layer2 mechanisms
+----------------------------------------------------------------------
+
+	It is also possible to use round-robin packet transmission,
+either in the balance-rr mode or using the round-robin xmit_hash_policy
+setting for balance-xor or 802.3ad modes to evenly stripe traffic across
+the set of slaves.  In conjuction with the src_mac_select option's
+"slave-src" value and a carefully configured network, it is possible to
+achieve high throughput using round robin.
+
+	The network here involves multiple hosts running bonding, all
+connected to a common switch, for example:
+
+  +--------+             +------------+             +--------+
+  |        |eth0    port1|            |port3    eth0|        |
+  | Host A +-------------+  switch    +-------------+ Host B |
+  | bond0  +-------------+            +-------------+ bond0  |
+  |        |eth1    port2|            |port4    eth1|        |
+  +--------+             +------------+             +--------+
+
+	In this configuration, the switch has ports 1 and 2 in one port
+channel group, and ports 3 and 4 in another port channel group.
+These channel groups are set to hash transmitted packets according to
+the source MAC address.
+
+	Host A and Host B each have a bond utilizing a round-robin
+transmit scheme, with src_mac_select set to "slave-src" and each slave's
+MAC address chosen to hash sequentially when run through the switch's
+source MAC address egress hash.
+
+	For clarity, only two slaves / ports are shown in the diagram.
+
+	In this manner, traffic sent from Host A to Host B will
+generally be evenly striped all the way through to Host B.  It is first
+sent round robin by Host A.  The switch will then hash on the source MAC
+address of the packets, whose MAC addresses have been manually selected
+to hash sequentially, thus the switch's egress port channel will tend to
+keep the traffic separated by port similarly to how it arrived (e.g.,
+packets from eth0 arriving on port1 will tend to go out port3, and
+simiarly for eth1, port2 and port4).
+
+	This scheme works best when the number of slaves and switch
+ports match at both ends.  Note that it will work with differing numbers
+of slaves, but the traffic balance may not be optimal, and it may be
+possible for a host with more slaves to overrun a host with fewer
+slaves.
+
+	According to usage experience and test results, balancing multiple
+(8-16) TCP sessions across bonded interface of 2 slaves utilizes 1.9-2.0
+Gbps in both directions, but with 4 slaves in bond - only 3.2-3.5 Gbps.
+When doing single unidirectional data transfer usually full aggregate
+bandwidth utilization is possible.
+
+	This usage scenario requires special switch configuration, as well
+as tuning TCP reordering related sysctl parameters.
+
 12.1.2 MT Link Monitoring for Single Switch Topology
 ----------------------------------------------------
 
diff -uprN -X linux-2.6/Documentation/dontdiff linux-2.6/drivers/net/bonding/bond_3ad.c linux-2.6.p/drivers/net/bonding/bond_3ad.c
--- linux-2.6/drivers/net/bonding/bond_3ad.c	2011-02-16 00:59:18.710282002 +0300
+++ linux-2.6.p/drivers/net/bonding/bond_3ad.c	2011-03-01 22:57:17.530282004 +0300
@@ -2419,7 +2419,7 @@ int bond_3ad_xmit_xor(struct sk_buff *sk
 		goto out;
 	}
 
-	slave_agg_no = bond->xmit_hash_policy(skb, slaves_in_agg);
+	slave_agg_no = bond->xmit_hash_policy(skb, slaves_in_agg, dev);
 
 	bond_for_each_slave(bond, slave, i) {
 		struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
diff -uprN -X linux-2.6/Documentation/dontdiff linux-2.6/drivers/net/bonding/bonding.h linux-2.6.p/drivers/net/bonding/bonding.h
--- linux-2.6/drivers/net/bonding/bonding.h	2011-02-16 00:59:18.720282002 +0300
+++ linux-2.6.p/drivers/net/bonding/bonding.h	2011-03-01 22:53:16.160281999 +0300
@@ -23,8 +23,8 @@
 #include "bond_3ad.h"
 #include "bond_alb.h"
 
-#define DRV_VERSION	"3.7.0"
-#define DRV_RELDATE	"June 2, 2010"
+#define DRV_VERSION	"3.8.0"
+#define DRV_RELDATE	"March 3, 2011"
 #define DRV_NAME	"bonding"
 #define DRV_DESCRIPTION	"Ethernet Channel Bonding Driver"
 
@@ -162,6 +162,7 @@ struct bond_params {
 	int tx_queues;
 	int all_slaves_active;
 	int resend_igmp;
+	int src_mac_select;
 };
 
 struct bond_parm_tbl {
@@ -235,7 +236,7 @@ struct bonding {
 #endif /* CONFIG_PROC_FS */
 	struct   list_head bond_list;
 	struct   netdev_hw_addr_list mc_list;
-	int      (*xmit_hash_policy)(struct sk_buff *, int);
+	int      (*xmit_hash_policy)(struct sk_buff *, int, struct net_device *);
 	__be32   master_ip;
 	u16      flags;
 	u16      rr_tx_counter;
@@ -308,6 +309,9 @@ static inline bool bond_is_lb(const stru
 #define BOND_ARP_VALIDATE_ALL		(BOND_ARP_VALIDATE_ACTIVE | \
 					 BOND_ARP_VALIDATE_BACKUP)
 
+#define BOND_SRC_MAC_DEFAULT		0
+#define BOND_SRC_MAC_SLAVE		1
+
 static inline int slave_do_arp_validate(struct bonding *bond,
 					struct slave *slave)
 {
@@ -402,6 +406,7 @@ extern const struct bond_parm_tbl arp_va
 extern const struct bond_parm_tbl fail_over_mac_tbl[];
 extern const struct bond_parm_tbl pri_reselect_tbl[];
 extern struct bond_parm_tbl ad_select_tbl[];
+extern const struct bond_parm_tbl src_mac_select_tbl[];
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 void bond_send_unsolicited_na(struct bonding *bond);
diff -uprN -X linux-2.6/Documentation/dontdiff linux-2.6/drivers/net/bonding/bond_main.c linux-2.6.p/drivers/net/bonding/bond_main.c
--- linux-2.6/drivers/net/bonding/bond_main.c	2011-02-16 00:59:18.720282002 +0300
+++ linux-2.6.p/drivers/net/bonding/bond_main.c	2011-03-01 23:00:24.770282003 +0300
@@ -111,6 +111,7 @@ static char *fail_over_mac;
 static int all_slaves_active = 0;
 static struct bond_params bonding_defaults;
 static int resend_igmp = BOND_DEFAULT_RESEND_IGMP;
+static char *src_mac_select;
 
 module_param(max_bonds, int, 0);
 MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
@@ -152,7 +153,7 @@ module_param(ad_select, charp, 0);
 MODULE_PARM_DESC(ad_select, "803.ad aggregation selection logic: stable (0, default), bandwidth (1), count (2)");
 module_param(xmit_hash_policy, charp, 0);
 MODULE_PARM_DESC(xmit_hash_policy, "XOR hashing method: 0 for layer 2 (default)"
-				   ", 1 for layer 3+4");
+				   ", 1 for layer 3+4, 3 for round-robin");
 module_param(arp_interval, int, 0);
 MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds");
 module_param_array(arp_ip_target, charp, NULL, 0);
@@ -167,6 +168,9 @@ MODULE_PARM_DESC(all_slaves_active, "Kee
 				     "0 for never (default), 1 for always.");
 module_param(resend_igmp, int, 0);
 MODULE_PARM_DESC(resend_igmp, "Number of IGMP membership reports to send on link failure");
+module_param(src_mac_select, charp, 0);
+MODULE_PARM_DESC(src_mac_select, "Source MAC selection mode: 0  or default (default),"
+				 "1 or slave-src to use slave's MAC as packet's src MAC");
 
 /*----------------------------- Global variables ----------------------------*/
 
@@ -206,6 +210,7 @@ const struct bond_parm_tbl xmit_hashtype
 {	"layer2",		BOND_XMIT_POLICY_LAYER2},
 {	"layer3+4",		BOND_XMIT_POLICY_LAYER34},
 {	"layer2+3",		BOND_XMIT_POLICY_LAYER23},
+{	"round-robin",		BOND_XMIT_POLICY_RR},
 {	NULL,			-1},
 };
 
@@ -238,6 +243,12 @@ struct bond_parm_tbl ad_select_tbl[] = {
 {	NULL,		-1},
 };
 
+const struct bond_parm_tbl src_mac_select_tbl[] = {
+{	"default",	BOND_SRC_MAC_DEFAULT},
+{	"slave-src",	BOND_SRC_MAC_SLAVE},
+{	NULL,		-1},
+};
+
 /*-------------------------- Forward declarations ---------------------------*/
 
 static void bond_send_gratuitous_arp(struct bonding *bond);
@@ -422,6 +433,7 @@ struct vlan_entry *bond_next_vlan(struct
 int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb,
 			struct net_device *slave_dev)
 {
+	struct ethhdr *eth_data;
 	skb->dev = slave_dev;
 	skb->priority = 1;
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -433,6 +445,15 @@ int bond_dev_queue_xmit(struct bonding *
 		slave_dev->priv_flags &= ~IFF_IN_NETPOLL;
 	} else
 #endif
+		if (bond->params.src_mac_select == BOND_SRC_MAC_SLAVE &&
+		   (skb->protocol == htons(ETH_P_IP) ||
+		   skb->protocol == htons(ETH_P_IPV6))) {
+			skb_reset_mac_header(skb);
+			eth_data = eth_hdr(skb);
+			memcpy(eth_data->h_source, slave_dev->perm_addr,
+				ETH_ALEN);
+		}
+
 		dev_queue_xmit(skb);
 
 	return 0;
@@ -3261,6 +3282,10 @@ static void bond_info_show_master(struct
 			bond->params.xmit_policy);
 	}
 
+	seq_printf(seq, "Source MAC select is: %s (%d)\n",
+		src_mac_select_tbl[bond->params.src_mac_select].modename,
+		bond->params.src_mac_select);
+
 	if (USES_PRIMARY(bond->params.mode)) {
 		seq_printf(seq, "Primary Slave: %s",
 			   (bond->primary_slave) ?
@@ -3717,7 +3742,8 @@ void bond_unregister_arp(struct bonding
  * Hash for the output device based upon layer 2 and layer 3 data. If
  * the packet is not IP mimic bond_xmit_hash_policy_l2()
  */
-static int bond_xmit_hash_policy_l23(struct sk_buff *skb, int count)
+static int bond_xmit_hash_policy_l23(struct sk_buff *skb, int count,
+					 struct net_device *bond_dev)
 {
 	struct ethhdr *data = (struct ethhdr *)skb->data;
 	struct iphdr *iph = ip_hdr(skb);
@@ -3735,7 +3761,8 @@ static int bond_xmit_hash_policy_l23(str
  * the packet is a frag or not TCP or UDP, just use layer 3 data.  If it is
  * altogether not IP, mimic bond_xmit_hash_policy_l2()
  */
-static int bond_xmit_hash_policy_l34(struct sk_buff *skb, int count)
+static int bond_xmit_hash_policy_l34(struct sk_buff *skb, int count,
+					 struct net_device *bond_dev)
 {
 	struct ethhdr *data = (struct ethhdr *)skb->data;
 	struct iphdr *iph = ip_hdr(skb);
@@ -3759,13 +3786,31 @@ static int bond_xmit_hash_policy_l34(str
 /*
  * Hash for the output device based upon layer 2 data
  */
-static int bond_xmit_hash_policy_l2(struct sk_buff *skb, int count)
+static int bond_xmit_hash_policy_l2(struct sk_buff *skb, int count,
+					 struct net_device *bond_dev)
 {
 	struct ethhdr *data = (struct ethhdr *)skb->data;
 
 	return (data->h_dest[5] ^ data->h_source[5]) % count;
 }
 
+/*
+ * Round-robin over all active slaves(one packet per slave) for IP and IPv6,
+ * otherwise mimic bond_xmit_hash_policy_l2() for IP IGMP traffic
+ */
+static int bond_xmit_hash_policy_rr(struct sk_buff *skb, int count,
+					 struct net_device *bond_dev)
+{
+	struct ethhdr *data = (struct ethhdr *)skb->data;
+	struct iphdr *iph = ip_hdr(skb);
+	struct bonding *bond = netdev_priv(bond_dev);
+	if ((iph->protocol == IPPROTO_IGMP) &&
+		(skb->protocol == htons(ETH_P_IP))) {
+			return (data->h_dest[5] ^ data->h_source[5]) % count;
+	}
+	return bond->rr_tx_counter++ % count;
+}
+
 /*-------------------------- Device entry points ----------------------------*/
 
 static int bond_open(struct net_device *bond_dev)
@@ -4395,7 +4440,8 @@ static int bond_xmit_xor(struct sk_buff
 	if (!BOND_IS_OK(bond))
 		goto out;
 
-	slave_no = bond->xmit_hash_policy(skb, bond->slave_cnt);
+	slave_no = bond->xmit_hash_policy(skb, bond->slave_cnt,
+					bond_dev);
 
 	bond_for_each_slave(bond, slave, i) {
 		slave_no--;
@@ -4492,6 +4538,9 @@ static void bond_set_xmit_hash_policy(st
 	case BOND_XMIT_POLICY_LAYER34:
 		bond->xmit_hash_policy = bond_xmit_hash_policy_l34;
 		break;
+	case BOND_XMIT_POLICY_RR:
+		bond->xmit_hash_policy = bond_xmit_hash_policy_rr;
+		break;
 	case BOND_XMIT_POLICY_LAYER2:
 	default:
 		bond->xmit_hash_policy = bond_xmit_hash_policy_l2;
diff -uprN -X linux-2.6/Documentation/dontdiff linux-2.6/drivers/net/bonding/bond_sysfs.c linux-2.6.p/drivers/net/bonding/bond_sysfs.c
--- linux-2.6/drivers/net/bonding/bond_sysfs.c	2011-02-08 16:03:02.950282003 +0300
+++ linux-2.6.p/drivers/net/bonding/bond_sysfs.c	2011-02-16 02:05:58.650281999 +0300
@@ -1643,6 +1643,55 @@ out:
 static DEVICE_ATTR(resend_igmp, S_IRUGO | S_IWUSR,
 		   bonding_show_resend_igmp, bonding_store_resend_igmp);
 
+/*
+ * Show and set the bonding src_mac_select param.
+ */
+
+static ssize_t bonding_show_src_mac_select(struct device *d,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct bonding *bond = to_bond(d);
+
+	return sprintf(buf, "%s %d\n",
+			src_mac_select_tbl[bond->params.src_mac_select].modename,
+			bond->params.src_mac_select);
+}
+
+static ssize_t bonding_store_src_mac_select(struct device *d,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int new_value, ret = count;
+	struct bonding *bond = to_bond(d);
+
+	if (bond->dev->flags & IFF_UP) {
+		pr_err("%s: Interface is up. Unable to update src mac select policy.\n",
+			bond->dev->name);
+		ret = -EPERM;
+		goto out;
+	}
+
+	new_value = bond_parse_parm(buf, src_mac_select_tbl);
+	if (new_value < 0)  {
+		pr_err("%s: Ignoring invalid src mac select policy value %.*s.\n",
+			bond->dev->name,
+			(int)strlen(buf) - 1, buf);
+		ret = -EINVAL;
+		goto out;
+	} else {
+		bond->params.src_mac_select = new_value;
+		pr_info("%s: setting src mac select policy to %s (%d).\n",
+			bond->dev->name,
+			src_mac_select_tbl[new_value].modename, new_value);
+	}
+out:
+	return ret;
+}
+
+static DEVICE_ATTR(src_mac_select, S_IRUGO | S_IWUSR,
+		bonding_show_src_mac_select, bonding_store_src_mac_select);
+
 static struct attribute *per_bond_attrs[] = {
 	&dev_attr_slaves.attr,
 	&dev_attr_mode.attr,
@@ -1671,6 +1720,7 @@ static struct attribute *per_bond_attrs[
 	&dev_attr_queue_id.attr,
 	&dev_attr_all_slaves_active.attr,
 	&dev_attr_resend_igmp.attr,
+	&dev_attr_src_mac_select.attr,
 	NULL,
 };
 
diff -uprN -X linux-2.6/Documentation/dontdiff linux-2.6/include/linux/if_bonding.h linux-2.6.p/include/linux/if_bonding.h
--- linux-2.6/include/linux/if_bonding.h	2011-02-16 00:59:18.720282002 +0300
+++ linux-2.6.p/include/linux/if_bonding.h	2011-03-01 23:00:56.610282019 +0300
@@ -91,6 +91,7 @@
 #define BOND_XMIT_POLICY_LAYER2		0 /* layer 2 (MAC only), default */
 #define BOND_XMIT_POLICY_LAYER34	1 /* layer 3+4 (IP ^ (TCP || UDP)) */
 #define BOND_XMIT_POLICY_LAYER23	2 /* layer 2+3 (IP ^ MAC) */
+#define BOND_XMIT_POLICY_RR		3 /* round-robin mode */
 
 typedef struct ifbond {
 	__s32 bond_mode;

^ permalink raw reply

* Re: [PATCH] bonding: added 802.3ad round-robin hashing policy and source mac selection mode
From: Oleg V. Ukhno @ 2011-03-01 22:38 UTC (permalink / raw)
  To: Jay Vosburgh; +Cc: netdev, David S. Miller
In-Reply-To: <14521.1298921393@death>

Hello Jay and David.
I've made all corrections to patch suggested and reposted it as 
http://patchwork.ozlabs.org/patch/84994/
Hope everything is ok now and this is the last retry for this patch:)


<cut to the end>

-- 
Best regards,
Oleg Ukhno.
Yandex LLC.


^ permalink raw reply

* [GIT PULL nf-2.6] IPVS
From: Simon Horman @ 2011-03-01 22:59 UTC (permalink / raw)
  To: lvs-devel, netdev, netfilter-devel, netfilter
  Cc: Hans Schillstrom, Julian Anastasov, Patrick McHardy, Simon Horman

Hi Patrick,

please consider pulling
git://git.kernel.org/pub/scm/linux/kernel/git/horms/lvs-test-2.6.git for-patrick
to get the following change from Julian. Please note that it is an nf-2.6
(that is 2.6.38-rc) change.

Julian Anastasov (1):
      ipvs: fix dst_lock locking on dest update

 net/netfilter/ipvs/ip_vs_ctl.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

^ permalink raw reply

* [PATCH] ipvs: fix dst_lock locking on dest update
From: Simon Horman @ 2011-03-01 22:59 UTC (permalink / raw)
  To: lvs-devel, netdev, netfilter-devel, netfilter
  Cc: Hans Schillstrom, Julian Anastasov, Patrick McHardy, Simon Horman
In-Reply-To: <1299020375-11362-1-git-send-email-horms@verge.net.au>

From: Julian Anastasov <ja@ssi.bg>

	Fix dst_lock usage in __ip_vs_update_dest. We need
_bh locking because destination is updated in user context.
Can cause lockups on frequent destination updates.
Problem reported by Simon Kirby. Bug was introduced
in 2.6.37 from the "ipvs: changes for local real server"
change.

Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Hans Schillstrom <hans@schillstrom.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
 net/netfilter/ipvs/ip_vs_ctl.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 22f7ad5..ba98e13 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -808,9 +808,9 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
 	dest->u_threshold = udest->u_threshold;
 	dest->l_threshold = udest->l_threshold;
 
-	spin_lock(&dest->dst_lock);
+	spin_lock_bh(&dest->dst_lock);
 	ip_vs_dst_reset(dest);
-	spin_unlock(&dest->dst_lock);
+	spin_unlock_bh(&dest->dst_lock);
 
 	if (add)
 		ip_vs_new_estimator(&dest->stats);
-- 
1.7.2.3


^ permalink raw reply related

* Re: [PATCH net-2.6] bonding: drop frames received with master's source MAC
From: Nicolas de Pesloüan @ 2011-03-01 23:08 UTC (permalink / raw)
  To: Jay Vosburgh
  Cc: Andy Gospodarek, netdev, David Miller, Herbert Xu, Jiri Pirko
In-Reply-To: <20893.1299018331@death>

Le 01/03/2011 23:25, Jay Vosburgh a écrit :
> Nicolas de Pesloüan 	<nicolas.2p.debian@gmail.com>  wrote:
>
>> Le 01/03/2011 19:16, Andy Gospodarek a écrit :
>>
>> [snip]
>>
>>> Knowing that I'm using an unmanaged switch with balance-rr probably
>>> helps understand how this is happening.  I'll clarify this however, so
>>> we are all on the same page.
>>>
>>> In my situation, eth2 and eth3 are in bond0.  When bond0 transmits the
>>> NS, let's say it goes out eth3.  Since it is a multicast frame my switch
>>> will broadcast this to all ports and eth2 will receive the frame with
>>> the source MAC address being the same as bond0's MAC address.  This
>>> frame is passed up the stack to the ipv6 layer and appears to be a
>>> response to the NS from another host and is dropped.
>>
>> 'sounds perfectly normal.
>>
>> This problem is described in detail in chapter 5.4.3 and appendix A of
>> RFC4862 "IPv6 Stateless Address Autoconfiguration".
>>
>> As this is clearly IPv6 related, it sounds normal from my point of view to
>> fix it at the ndisc_recv_ns() level.
>
> 	Andy's immediate problem is IPv6 related, but the issue itself
> is generic: how to deal with broadcast / multicasts arriving at a -rr or
> -xor bond, because we do not and cannot know if the switch is going to
> flood to the slaves or not.  There may be other instances wherein that
> bonus copy of some packet confuses things.

Agreed, even if the only known instances that currently expose the problem is IPv6.

Anyway, let's try and fix it at the bonding level...

> 	My view is that -rr and -xor are intended to interoperate with
> Etherchannel.  Yes, they will often work tolerably well when connected
> to a non-Etherchannel switch.  But, if the host and the switch are not
> in agreement on the link aggregation status of the ports, some level of
> misbehavior is expected.  If that misbehavior can be corrected without
> adversely affecting a properly configured host and switch, then I don't
> see much problem with fixing it.
>
> 	For the IPv6 case here, I think there's a problem with any fix,
> and that is that there's no way for bonding to know if the switch ports
> are configured properly or not.  I'm using "properly" to mean that the
> switch ports corresponding to the bonding slaves are configured into an
> Etherchannel-type channel group.
>
> 	If the switch ports are grouped, then if IPv6 sees one of these
> messages coming in, it's actually a duplicate detection.  This because
> the switch won't loop the broadcast / multicast back around to a member
> of the channel group.
>
> 	If the switch ports are not grouped, then the switch will
> happily send broadcasts and multicasts to all ports of the bond, because
> it doesn't know about the aggregation.  In this case, I suspect there's
> no way to reliably determine if the incoming packet is a switch artifact
> or an actual duplicate detection.  Anybody know for sure if this is the
> case?
>
> 	For the generic case, I'm not seeing a way to distinguish actual
> repeated packets from switch artifact duplicate packets without adding
> another knob to bonding to tell it if the switch does etherchannel or
> not (which I'm not in favor of doing).

I originally thought about such knob and agree with you that we should avoid adding one more...

>> Quoting the RFC:
>>
>>   "In those cases where the hardware cannot suppress loopbacks, however,
>>    one possible software heuristic to filter out unwanted loopbacks is
>>    to discard any received packet whose link-layer source address is the
>>    same as the receiving interface's.  There is even a link-layer
>>    specification that requires that any such packets be discarded
>>    [IEEE802.11].  Unfortunately, use of that criteria also results in
>>    the discarding of all packets sent by another node using the same
>>    link-layer address.  Duplicate Address Detection will fail on
>>    interfaces that filter received packets in this manner:
>>
>>    [snip]
>>
>>    Thus, to perform Duplicate Address Detection correctly in the case
>>    where two interfaces are using the same link-layer address, an
>>    implementation must have a good understanding of the interface's
>>    multicast loopback semantics, and the interface cannot discard
>>    received packets simply because the source link-layer address is the
>>    same as the interface's."
>>
>> So, simply dropping frames whose source MAC == local MAC is apparently not the right solution.
>
> 	I tend to agree here, because this would break DAD for properly
> configured (meaning etherchannel on the switch ports) installations.
>
> 	Is there a way to fix bonding and/or ndisc_recv_ns to work
> correctly for both cases (have/don't have etherchannel on the switch)?

Can we imagine that, at the time we change the bonding mode to -rr or -xor, we simply brodcast or 
multicast one or two frames with some random data and wait to see whether we receive the frame back? 
If we receive at least one frame with the same random data, in one of the slaves interface for this 
bonding, we know for sure the switch configuration is not "multicast loop safe". Bonding already 
send ARP requests/replies in many situations. Adding one broadcast/multicast frame at bond setup 
time is probably acceptable.

And to ensure consistent results, we need to send such broadcast/multicast every time the link goes 
up for an already enslaved slave. This is not perfect, as the switch topology may change in a way 
that won't be detected by bonding, but still cause a new multicast loop, but...

Knowing the switch configuration is not "multicast loop safe", we can, at a minimum, issue a 
warning, telling the user she should expect strange behaviors, like false duplicate address detection.

And we can probably use this information into the should-drop logic, for mode that lack "inactive" 
slaves.

	Nicolas.

^ permalink raw reply

* [PATCH 0/8] Simplify IPSEC lookup interfaces.
From: David Miller @ 2011-03-01 23:11 UTC (permalink / raw)
  To: netdev


We have two major uglies in our IPSEC rule resolution main entrypoint(s).

First, we have two interfaces, xfrm_lookup and __xfrm_lookup solely so
that callers can implement blackhole route resolution locally.  This
results in a lot of duplicated code.

But it's unnecessary as we can simply make this an afinfo->op()

Secondly we have all of this magic to propagate "can sleep in this
context" state via messy arguments.  Store this inside of the flow
flags instead of via extra arguments.

Now we are down to one interface, xfrm_lookup().

Signed-off-by: David S. Miller <davem@davemloft.net>

^ permalink raw reply

* [PATCH 1/8] ipv4: Can final ip_route_connect() arg to boolean "can_sleep".
From: David Miller @ 2011-03-01 23:11 UTC (permalink / raw)
  To: netdev


Since that's what the current vague "flags" thing means.

Signed-off-by: David S. Miller <davem@davemloft.net>
---
 include/net/route.h |    4 ++--
 net/dccp/ipv4.c     |    2 +-
 net/ipv4/af_inet.c  |    2 +-
 net/ipv4/datagram.c |    2 +-
 net/ipv4/tcp_ipv4.c |    2 +-
 net/l2tp/l2tp_ip.c  |    2 +-
 6 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/include/net/route.h b/include/net/route.h
index b3f89ad..5e0826d 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -168,7 +168,7 @@ static inline char rt_tos2priority(u8 tos)
 static inline int ip_route_connect(struct rtable **rp, __be32 dst,
 				   __be32 src, u32 tos, int oif, u8 protocol,
 				   __be16 sport, __be16 dport, struct sock *sk,
-				   int flags)
+				   bool can_sleep)
 {
 	struct flowi fl = { .oif = oif,
 			    .mark = sk->sk_mark,
@@ -196,7 +196,7 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst,
 		*rp = NULL;
 	}
 	security_sk_classify_flow(sk, &fl);
-	return ip_route_output_flow(net, rp, &fl, sk, flags);
+	return ip_route_output_flow(net, rp, &fl, sk, can_sleep ? 1 : 0);
 }
 
 static inline int ip_route_newports(struct rtable **rp, u8 protocol,
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 9379891..8372d5c 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -69,7 +69,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 	tmp = ip_route_connect(&rt, nexthop, inet->inet_saddr,
 			       RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
 			       IPPROTO_DCCP,
-			       orig_sport, orig_dport, sk, 1);
+			       orig_sport, orig_dport, sk, true);
 	if (tmp < 0)
 		return tmp;
 
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 7ceb804..d16687d 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1115,7 +1115,7 @@ static int inet_sk_reselect_saddr(struct sock *sk)
 			       RT_CONN_FLAGS(sk),
 			       sk->sk_bound_dev_if,
 			       sk->sk_protocol,
-			       inet->inet_sport, inet->inet_dport, sk, 0);
+			       inet->inet_sport, inet->inet_dport, sk, false);
 	if (err)
 		return err;
 
diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c
index 174be6c..eaee1ed 100644
--- a/net/ipv4/datagram.c
+++ b/net/ipv4/datagram.c
@@ -49,7 +49,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 	err = ip_route_connect(&rt, usin->sin_addr.s_addr, saddr,
 			       RT_CONN_FLAGS(sk), oif,
 			       sk->sk_protocol,
-			       inet->inet_sport, usin->sin_port, sk, 1);
+			       inet->inet_sport, usin->sin_port, sk, true);
 	if (err) {
 		if (err == -ENETUNREACH)
 			IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 27a0cc8..05bc6d9 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -173,7 +173,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 	tmp = ip_route_connect(&rt, nexthop, inet->inet_saddr,
 			       RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
 			       IPPROTO_TCP,
-			       orig_sport, orig_dport, sk, 1);
+			       orig_sport, orig_dport, sk, true);
 	if (tmp < 0) {
 		if (tmp == -ENETUNREACH)
 			IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
index 110efb7..28e876a 100644
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -323,7 +323,7 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len
 	rc = ip_route_connect(&rt, lsa->l2tp_addr.s_addr, saddr,
 			      RT_CONN_FLAGS(sk), oif,
 			      IPPROTO_L2TP,
-			      0, 0, sk, 1);
+			      0, 0, sk, true);
 	if (rc) {
 		if (rc == -ENETUNREACH)
 			IP_INC_STATS_BH(&init_net, IPSTATS_MIB_OUTNOROUTES);
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 2/8] ipv4: Make final arg to ip_route_output_flow to be boolean "can_sleep"
From: David Miller @ 2011-03-01 23:11 UTC (permalink / raw)
  To: netdev


Since that is what the current vague "flags" argument means.

Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/infiniband/hw/cxgb3/iwch_cm.c |    2 +-
 drivers/infiniband/hw/cxgb4/cm.c      |    2 +-
 drivers/scsi/cxgbi/libcxgbi.c         |    2 +-
 include/net/route.h                   |    6 +++---
 net/dccp/ipv4.c                       |    2 +-
 net/ipv4/af_inet.c                    |    2 +-
 net/ipv4/inet_connection_sock.c       |    2 +-
 net/ipv4/ip_output.c                  |    2 +-
 net/ipv4/raw.c                        |    2 +-
 net/ipv4/route.c                      |    6 +++---
 net/ipv4/udp.c                        |    2 +-
 net/l2tp/l2tp_ip.c                    |    2 +-
 12 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index d02dcc6..c7f776c 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -354,7 +354,7 @@ static struct rtable *find_route(struct t3cdev *dev, __be32 local_ip,
 			  }
 	};
 
-	if (ip_route_output_flow(&init_net, &rt, &fl, NULL, 0))
+	if (ip_route_output_flow(&init_net, &rt, &fl, NULL, false))
 		return NULL;
 	return rt;
 }
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 8b00e6c..5542c99 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -331,7 +331,7 @@ static struct rtable *find_route(struct c4iw_dev *dev, __be32 local_ip,
 			  }
 	};
 
-	if (ip_route_output_flow(&init_net, &rt, &fl, NULL, 0))
+	if (ip_route_output_flow(&init_net, &rt, &fl, NULL, false))
 		return NULL;
 	return rt;
 }
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index d2ad3d6..fabca75 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -470,7 +470,7 @@ static struct rtable *find_route_ipv4(__be32 saddr, __be32 daddr,
 			}
 	};
 
-	if (ip_route_output_flow(&init_net, &rt, &fl, NULL, 0))
+	if (ip_route_output_flow(&init_net, &rt, &fl, NULL, false))
 		return NULL;
 
 	return rt;
diff --git a/include/net/route.h b/include/net/route.h
index 5e0826d..6de4333 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -120,7 +120,7 @@ extern void		rt_cache_flush(struct net *net, int how);
 extern void		rt_cache_flush_batch(struct net *net);
 extern int		__ip_route_output_key(struct net *, struct rtable **, const struct flowi *flp);
 extern int		ip_route_output_key(struct net *, struct rtable **, struct flowi *flp);
-extern int		ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk, int flags);
+extern int		ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk, bool can_sleep);
 
 extern int ip_route_input_common(struct sk_buff *skb, __be32 dst, __be32 src,
 				 u8 tos, struct net_device *devin, bool noref);
@@ -196,7 +196,7 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst,
 		*rp = NULL;
 	}
 	security_sk_classify_flow(sk, &fl);
-	return ip_route_output_flow(net, rp, &fl, sk, can_sleep ? 1 : 0);
+	return ip_route_output_flow(net, rp, &fl, sk, can_sleep);
 }
 
 static inline int ip_route_newports(struct rtable **rp, u8 protocol,
@@ -220,7 +220,7 @@ static inline int ip_route_newports(struct rtable **rp, u8 protocol,
 		ip_rt_put(*rp);
 		*rp = NULL;
 		security_sk_classify_flow(sk, &fl);
-		return ip_route_output_flow(sock_net(sk), rp, &fl, sk, 0);
+		return ip_route_output_flow(sock_net(sk), rp, &fl, sk, false);
 	}
 	return 0;
 }
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 8372d5c..3d4b82f 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -475,7 +475,7 @@ static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk,
 			  };
 
 	security_skb_classify_flow(skb, &fl);
-	if (ip_route_output_flow(net, &rt, &fl, sk, 0)) {
+	if (ip_route_output_flow(net, &rt, &fl, sk, false)) {
 		IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES);
 		return NULL;
 	}
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index d16687d..7d90fe0 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1174,7 +1174,7 @@ int inet_sk_rebuild_header(struct sock *sk)
 	};
 
 	security_sk_classify_flow(sk, &fl);
-	err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0);
+	err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, false);
 }
 	if (!err)
 		sk_setup_caps(sk, &rt->dst);
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 97e5fb7..0caeb69 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -369,7 +369,7 @@ struct dst_entry *inet_csk_route_req(struct sock *sk,
 	struct net *net = sock_net(sk);
 
 	security_req_classify_flow(req, &fl);
-	if (ip_route_output_flow(net, &rt, &fl, sk, 0))
+	if (ip_route_output_flow(net, &rt, &fl, sk, false))
 		goto no_route;
 	if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
 		goto route_err;
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 460308c..e6905c5 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -355,7 +355,7 @@ int ip_queue_xmit(struct sk_buff *skb)
 			 * itself out.
 			 */
 			security_sk_classify_flow(sk, &fl);
-			if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0))
+			if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, false))
 				goto no_route;
 		}
 		sk_setup_caps(sk, &rt->dst);
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 6390ba2..e185765 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -563,7 +563,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 		}
 
 		security_sk_classify_flow(sk, &fl);
-		err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 1);
+		err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, true);
 	}
 	if (err)
 		goto done;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 52b077d..1ac3eca 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2720,7 +2720,7 @@ static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi
 }
 
 int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
-			 struct sock *sk, int flags)
+			 struct sock *sk, bool can_sleep)
 {
 	int err;
 
@@ -2733,7 +2733,7 @@ int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
 		if (!flp->fl4_dst)
 			flp->fl4_dst = (*rp)->rt_dst;
 		err = __xfrm_lookup(net, (struct dst_entry **)rp, flp, sk,
-				    flags ? XFRM_LOOKUP_WAIT : 0);
+				    can_sleep ? XFRM_LOOKUP_WAIT : 0);
 		if (err == -EREMOTE)
 			err = ipv4_dst_blackhole(net, rp, flp);
 
@@ -2746,7 +2746,7 @@ EXPORT_SYMBOL_GPL(ip_route_output_flow);
 
 int ip_route_output_key(struct net *net, struct rtable **rp, struct flowi *flp)
 {
-	return ip_route_output_flow(net, rp, flp, NULL, 0);
+	return ip_route_output_flow(net, rp, flp, NULL, false);
 }
 EXPORT_SYMBOL(ip_route_output_key);
 
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 8155d6e..790187b 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -920,7 +920,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 		struct net *net = sock_net(sk);
 
 		security_sk_classify_flow(sk, &fl);
-		err = ip_route_output_flow(net, &rt, &fl, sk, 1);
+		err = ip_route_output_flow(net, &rt, &fl, sk, true);
 		if (err) {
 			if (err == -ENETUNREACH)
 				IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES);
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
index 28e876a..7744a8e 100644
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -489,7 +489,7 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m
 			 * itself out.
 			 */
 			security_sk_classify_flow(sk, &fl);
-			if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0))
+			if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, false))
 				goto no_route;
 		}
 		sk_setup_caps(sk, &rt->dst);
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 3/8] net: Add FLOWI_FLAG_CAN_SLEEP.
From: David Miller @ 2011-03-01 23:11 UTC (permalink / raw)
  To: netdev


And set is in contexts where the route resolution can sleep.

Signed-off-by: David S. Miller <davem@davemloft.net>
---
 include/net/flow.h    |    1 +
 include/net/route.h   |    2 ++
 net/ipv4/raw.c        |    3 ++-
 net/ipv4/udp.c        |    6 ++++--
 net/ipv6/ip6_output.c |    2 ++
 5 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/include/net/flow.h b/include/net/flow.h
index f2080e6..fd04138 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -50,6 +50,7 @@ struct flowi {
 	__u8	flags;
 #define FLOWI_FLAG_ANYSRC		0x01
 #define FLOWI_FLAG_PRECOW_METRICS	0x02
+#define FLOWI_FLAG_CAN_SLEEP		0x04
 	union {
 		struct {
 			__be16	sport;
diff --git a/include/net/route.h b/include/net/route.h
index 6de4333..1be5c05 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -185,6 +185,8 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst,
 		fl.flags |= FLOWI_FLAG_ANYSRC;
 	if (protocol == IPPROTO_TCP)
 		fl.flags |= FLOWI_FLAG_PRECOW_METRICS;
+	if (can_sleep)
+		fl.flags |= FLOWI_FLAG_CAN_SLEEP;
 
 	if (!dst || !src) {
 		err = __ip_route_output_key(net, rp, &fl);
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index e185765..e8e8613 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -555,7 +555,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 				    .fl4_tos = tos,
 				    .proto = inet->hdrincl ? IPPROTO_RAW :
 							     sk->sk_protocol,
-				  };
+				    .flags = FLOWI_FLAG_CAN_SLEEP,
+		};
 		if (!inet->hdrincl) {
 			err = raw_probe_proto_opt(&fl, msg);
 			if (err)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 790187b..c6bcc93 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -914,9 +914,11 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 				    .fl4_src = saddr,
 				    .fl4_tos = tos,
 				    .proto = sk->sk_protocol,
-				    .flags = inet_sk_flowi_flags(sk),
+				    .flags = (inet_sk_flowi_flags(sk) |
+					      FLOWI_FLAG_CAN_SLEEP),
 				    .fl_ip_sport = inet->inet_sport,
-				    .fl_ip_dport = dport };
+				    .fl_ip_dport = dport
+		};
 		struct net *net = sock_net(sk);
 
 		security_sk_classify_flow(sk, &fl);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 28209b2..77b1942 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1026,6 +1026,7 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi *fl,
 	if (final_dst)
 		ipv6_addr_copy(&fl->fl6_dst, final_dst);
 	if (want_blackhole) {
+		fl->flags |= FLOWI_FLAG_CAN_SLEEP;
 		err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, XFRM_LOOKUP_WAIT);
 		if (err == -EREMOTE)
 			err = ip6_dst_blackhole(sk, &dst, fl);
@@ -1070,6 +1071,7 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi *fl,
 	if (final_dst)
 		ipv6_addr_copy(&fl->fl6_dst, final_dst);
 	if (want_blackhole) {
+		fl->flags |= FLOWI_FLAG_CAN_SLEEP;
 		err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, XFRM_LOOKUP_WAIT);
 		if (err == -EREMOTE)
 			err = ip6_dst_blackhole(sk, &dst, fl);
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 4/8] ipv4: Kill can_sleep arg to ip_route_output_flow()
From: David Miller @ 2011-03-01 23:11 UTC (permalink / raw)
  To: netdev


This boolean state is now available in the flow flags.

Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/infiniband/hw/cxgb3/iwch_cm.c |    2 +-
 drivers/infiniband/hw/cxgb4/cm.c      |    2 +-
 drivers/scsi/cxgbi/libcxgbi.c         |    2 +-
 include/net/route.h                   |    6 +++---
 net/dccp/ipv4.c                       |    2 +-
 net/ipv4/af_inet.c                    |    2 +-
 net/ipv4/inet_connection_sock.c       |    2 +-
 net/ipv4/ip_output.c                  |    2 +-
 net/ipv4/raw.c                        |    2 +-
 net/ipv4/route.c                      |    7 ++++---
 net/ipv4/udp.c                        |    2 +-
 net/l2tp/l2tp_ip.c                    |    2 +-
 12 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index c7f776c..e654285 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -354,7 +354,7 @@ static struct rtable *find_route(struct t3cdev *dev, __be32 local_ip,
 			  }
 	};
 
-	if (ip_route_output_flow(&init_net, &rt, &fl, NULL, false))
+	if (ip_route_output_flow(&init_net, &rt, &fl, NULL))
 		return NULL;
 	return rt;
 }
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 5542c99..7e0484f 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -331,7 +331,7 @@ static struct rtable *find_route(struct c4iw_dev *dev, __be32 local_ip,
 			  }
 	};
 
-	if (ip_route_output_flow(&init_net, &rt, &fl, NULL, false))
+	if (ip_route_output_flow(&init_net, &rt, &fl, NULL))
 		return NULL;
 	return rt;
 }
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index fabca75..261aa81 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -470,7 +470,7 @@ static struct rtable *find_route_ipv4(__be32 saddr, __be32 daddr,
 			}
 	};
 
-	if (ip_route_output_flow(&init_net, &rt, &fl, NULL, false))
+	if (ip_route_output_flow(&init_net, &rt, &fl, NULL))
 		return NULL;
 
 	return rt;
diff --git a/include/net/route.h b/include/net/route.h
index 1be5c05..923e670 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -120,7 +120,7 @@ extern void		rt_cache_flush(struct net *net, int how);
 extern void		rt_cache_flush_batch(struct net *net);
 extern int		__ip_route_output_key(struct net *, struct rtable **, const struct flowi *flp);
 extern int		ip_route_output_key(struct net *, struct rtable **, struct flowi *flp);
-extern int		ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk, bool can_sleep);
+extern int		ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk);
 
 extern int ip_route_input_common(struct sk_buff *skb, __be32 dst, __be32 src,
 				 u8 tos, struct net_device *devin, bool noref);
@@ -198,7 +198,7 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst,
 		*rp = NULL;
 	}
 	security_sk_classify_flow(sk, &fl);
-	return ip_route_output_flow(net, rp, &fl, sk, can_sleep);
+	return ip_route_output_flow(net, rp, &fl, sk);
 }
 
 static inline int ip_route_newports(struct rtable **rp, u8 protocol,
@@ -222,7 +222,7 @@ static inline int ip_route_newports(struct rtable **rp, u8 protocol,
 		ip_rt_put(*rp);
 		*rp = NULL;
 		security_sk_classify_flow(sk, &fl);
-		return ip_route_output_flow(sock_net(sk), rp, &fl, sk, false);
+		return ip_route_output_flow(sock_net(sk), rp, &fl, sk);
 	}
 	return 0;
 }
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 3d4b82f..a8ff955 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -475,7 +475,7 @@ static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk,
 			  };
 
 	security_skb_classify_flow(skb, &fl);
-	if (ip_route_output_flow(net, &rt, &fl, sk, false)) {
+	if (ip_route_output_flow(net, &rt, &fl, sk)) {
 		IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES);
 		return NULL;
 	}
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 7d90fe0..44513bb 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1174,7 +1174,7 @@ int inet_sk_rebuild_header(struct sock *sk)
 	};
 
 	security_sk_classify_flow(sk, &fl);
-	err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, false);
+	err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk);
 }
 	if (!err)
 		sk_setup_caps(sk, &rt->dst);
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 0caeb69..7f85d4a 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -369,7 +369,7 @@ struct dst_entry *inet_csk_route_req(struct sock *sk,
 	struct net *net = sock_net(sk);
 
 	security_req_classify_flow(req, &fl);
-	if (ip_route_output_flow(net, &rt, &fl, sk, false))
+	if (ip_route_output_flow(net, &rt, &fl, sk))
 		goto no_route;
 	if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
 		goto route_err;
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index e6905c5..68dbe2d 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -355,7 +355,7 @@ int ip_queue_xmit(struct sk_buff *skb)
 			 * itself out.
 			 */
 			security_sk_classify_flow(sk, &fl);
-			if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, false))
+			if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk))
 				goto no_route;
 		}
 		sk_setup_caps(sk, &rt->dst);
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index e8e8613..d7a2d1e 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -564,7 +564,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 		}
 
 		security_sk_classify_flow(sk, &fl);
-		err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, true);
+		err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk);
 	}
 	if (err)
 		goto done;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 1ac3eca..7846265 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2720,7 +2720,7 @@ static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi
 }
 
 int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
-			 struct sock *sk, bool can_sleep)
+			 struct sock *sk)
 {
 	int err;
 
@@ -2733,7 +2733,8 @@ int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
 		if (!flp->fl4_dst)
 			flp->fl4_dst = (*rp)->rt_dst;
 		err = __xfrm_lookup(net, (struct dst_entry **)rp, flp, sk,
-				    can_sleep ? XFRM_LOOKUP_WAIT : 0);
+				    ((flp->flags & FLOWI_FLAG_CAN_SLEEP) ?
+				     XFRM_LOOKUP_WAIT : 0));
 		if (err == -EREMOTE)
 			err = ipv4_dst_blackhole(net, rp, flp);
 
@@ -2746,7 +2747,7 @@ EXPORT_SYMBOL_GPL(ip_route_output_flow);
 
 int ip_route_output_key(struct net *net, struct rtable **rp, struct flowi *flp)
 {
-	return ip_route_output_flow(net, rp, flp, NULL, false);
+	return ip_route_output_flow(net, rp, flp, NULL);
 }
 EXPORT_SYMBOL(ip_route_output_key);
 
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index c6bcc93..ed9a5b7 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -922,7 +922,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 		struct net *net = sock_net(sk);
 
 		security_sk_classify_flow(sk, &fl);
-		err = ip_route_output_flow(net, &rt, &fl, sk, true);
+		err = ip_route_output_flow(net, &rt, &fl, sk);
 		if (err) {
 			if (err == -ENETUNREACH)
 				IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES);
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
index 7744a8e..5381ceb 100644
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -489,7 +489,7 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m
 			 * itself out.
 			 */
 			security_sk_classify_flow(sk, &fl);
-			if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, false))
+			if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk))
 				goto no_route;
 		}
 		sk_setup_caps(sk, &rt->dst);
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 5/8]ipv6: Change final dst lookup arg name to "can_sleep"
From: David Miller @ 2011-03-01 23:11 UTC (permalink / raw)
  To: netdev


Since it indicates whether we are invoked from a sleepable
context or not.

Signed-off-by: David S. Miller <davem@davemloft.net>
---
 include/net/ipv6.h    |    4 ++--
 net/ipv6/ip6_output.c |   12 ++++++------
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 1fc5631..8f78aac 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -515,11 +515,11 @@ extern int			ip6_dst_lookup(struct sock *sk,
 extern struct dst_entry *	ip6_dst_lookup_flow(struct sock *sk,
 						    struct flowi *fl,
 						    const struct in6_addr *final_dst,
-						    bool want_blackhole);
+						    bool can_sleep);
 extern struct dst_entry *	ip6_sk_dst_lookup_flow(struct sock *sk,
 						       struct flowi *fl,
 						       const struct in6_addr *final_dst,
-						       bool want_blackhole);
+						       bool can_sleep);
 extern int			ip6_dst_blackhole(struct sock *sk,
 						  struct dst_entry **dst,
 						  struct flowi *fl);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 77b1942..b5f8769 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1006,7 +1006,7 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup);
  *	@sk: socket which provides route info
  *	@fl: flow to lookup
  *	@final_dst: final destination address for ipsec lookup
- *	@want_blackhole: IPSEC blackhole handling desired
+ *	@can_sleep: we are in a sleepable context
  *
  *	This function performs a route lookup on the given flow.
  *
@@ -1015,7 +1015,7 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup);
  */
 struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi *fl,
 				      const struct in6_addr *final_dst,
-				      bool want_blackhole)
+				      bool can_sleep)
 {
 	struct dst_entry *dst = NULL;
 	int err;
@@ -1025,7 +1025,7 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi *fl,
 		return ERR_PTR(err);
 	if (final_dst)
 		ipv6_addr_copy(&fl->fl6_dst, final_dst);
-	if (want_blackhole) {
+	if (can_sleep) {
 		fl->flags |= FLOWI_FLAG_CAN_SLEEP;
 		err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, XFRM_LOOKUP_WAIT);
 		if (err == -EREMOTE)
@@ -1046,7 +1046,7 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow);
  *	@sk: socket which provides the dst cache and route info
  *	@fl: flow to lookup
  *	@final_dst: final destination address for ipsec lookup
- *	@want_blackhole: IPSEC blackhole handling desired
+ *	@can_sleep: we are in a sleepable context
  *
  *	This function performs a route lookup on the given flow with the
  *	possibility of using the cached route in the socket if it is valid.
@@ -1058,7 +1058,7 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow);
  */
 struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi *fl,
 					 const struct in6_addr *final_dst,
-					 bool want_blackhole)
+					 bool can_sleep)
 {
 	struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie);
 	int err;
@@ -1070,7 +1070,7 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi *fl,
 		return ERR_PTR(err);
 	if (final_dst)
 		ipv6_addr_copy(&fl->fl6_dst, final_dst);
-	if (want_blackhole) {
+	if (can_sleep) {
 		fl->flags |= FLOWI_FLAG_CAN_SLEEP;
 		err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, XFRM_LOOKUP_WAIT);
 		if (err == -EREMOTE)
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 6/8] xfrm: Kill XFRM_LOOKUP_WAIT flag.
From: David Miller @ 2011-03-01 23:11 UTC (permalink / raw)
  To: netdev


This can be determined from the flow flags instead.

Signed-off-by: David S. Miller <davem@davemloft.net>
---
 include/net/dst.h      |    3 +--
 net/decnet/dn_route.c  |    5 +++--
 net/ipv4/route.c       |    4 +---
 net/ipv6/ip6_output.c  |    4 ++--
 net/xfrm/xfrm_policy.c |    2 +-
 5 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/include/net/dst.h b/include/net/dst.h
index 4fedffd..15d67c8 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -421,8 +421,7 @@ extern void		dst_init(void);
 
 /* Flags for xfrm_lookup flags argument. */
 enum {
-	XFRM_LOOKUP_WAIT = 1 << 0,
-	XFRM_LOOKUP_ICMP = 1 << 1,
+	XFRM_LOOKUP_ICMP = 1 << 0,
 };
 
 struct flowi;
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 06c054d..0877147 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -1233,8 +1233,9 @@ int dn_route_output_sock(struct dst_entry **pprt, struct flowi *fl, struct sock
 
 	err = __dn_route_output_key(pprt, fl, flags & MSG_TRYHARD);
 	if (err == 0 && fl->proto) {
-		err = xfrm_lookup(&init_net, pprt, fl, sk,
-				 (flags & MSG_DONTWAIT) ? 0 : XFRM_LOOKUP_WAIT);
+		if (!(flags & MSG_DONTWAIT))
+			fl->flags |= FLOWI_FLAG_CAN_SLEEP;
+		err = xfrm_lookup(&init_net, pprt, fl, sk, 0);
 	}
 	return err;
 }
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 7846265..23d2050 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2732,9 +2732,7 @@ int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
 			flp->fl4_src = (*rp)->rt_src;
 		if (!flp->fl4_dst)
 			flp->fl4_dst = (*rp)->rt_dst;
-		err = __xfrm_lookup(net, (struct dst_entry **)rp, flp, sk,
-				    ((flp->flags & FLOWI_FLAG_CAN_SLEEP) ?
-				     XFRM_LOOKUP_WAIT : 0));
+		err = __xfrm_lookup(net, (struct dst_entry **)rp, flp, sk, 0);
 		if (err == -EREMOTE)
 			err = ipv4_dst_blackhole(net, rp, flp);
 
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index b5f8769..faf7b9d 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1027,7 +1027,7 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi *fl,
 		ipv6_addr_copy(&fl->fl6_dst, final_dst);
 	if (can_sleep) {
 		fl->flags |= FLOWI_FLAG_CAN_SLEEP;
-		err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, XFRM_LOOKUP_WAIT);
+		err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
 		if (err == -EREMOTE)
 			err = ip6_dst_blackhole(sk, &dst, fl);
 		if (err)
@@ -1072,7 +1072,7 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi *fl,
 		ipv6_addr_copy(&fl->fl6_dst, final_dst);
 	if (can_sleep) {
 		fl->flags |= FLOWI_FLAG_CAN_SLEEP;
-		err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, XFRM_LOOKUP_WAIT);
+		err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
 		if (err == -EREMOTE)
 			err = ip6_dst_blackhole(sk, &dst, fl);
 		if (err)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 41a91d2..f4c7467 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1831,7 +1831,7 @@ restart:
 			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
 			return -EREMOTE;
 		}
-		if (flags & XFRM_LOOKUP_WAIT) {
+		if (fl->flags & FLOWI_FLAG_CAN_SLEEP) {
 			DECLARE_WAITQUEUE(wait, current);
 
 			add_wait_queue(&net->xfrm.km_waitq, &wait);
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 7/8] ipv6: Normalize arguments to ip6_dst_blackhole().
From: David Miller @ 2011-03-01 23:11 UTC (permalink / raw)
  To: netdev


Return a dst pointer which is potentitally error encoded.

Don't pass original dst pointer by reference, pass a struct net
instead of a socket, and elide the flow argument since it is
unnecessary.

Signed-off-by: David S. Miller <davem@davemloft.net>
---
 include/net/ipv6.h    |    5 ++---
 net/ipv6/ip6_output.c |    4 ++--
 net/ipv6/route.c      |   12 +++++-------
 3 files changed, 9 insertions(+), 12 deletions(-)

diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 8f78aac..5d125c1 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -520,9 +520,8 @@ extern struct dst_entry *	ip6_sk_dst_lookup_flow(struct sock *sk,
 						       struct flowi *fl,
 						       const struct in6_addr *final_dst,
 						       bool can_sleep);
-extern int			ip6_dst_blackhole(struct sock *sk,
-						  struct dst_entry **dst,
-						  struct flowi *fl);
+extern struct dst_entry *	ip6_dst_blackhole(struct net *net,
+						  struct dst_entry *orig_dst);
 
 /*
  *	skb processing functions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index faf7b9d..ac16f3b 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1029,7 +1029,7 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi *fl,
 		fl->flags |= FLOWI_FLAG_CAN_SLEEP;
 		err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
 		if (err == -EREMOTE)
-			err = ip6_dst_blackhole(sk, &dst, fl);
+			return ip6_dst_blackhole(sock_net(sk), dst);
 		if (err)
 			return ERR_PTR(err);
 	} else {
@@ -1074,7 +1074,7 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi *fl,
 		fl->flags |= FLOWI_FLAG_CAN_SLEEP;
 		err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
 		if (err == -EREMOTE)
-			err = ip6_dst_blackhole(sk, &dst, fl);
+			return ip6_dst_blackhole(sock_net(sk), dst);
 		if (err)
 			return ERR_PTR(err);
 	} else {
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 7e9443f..cf6fdea 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -870,11 +870,10 @@ struct dst_entry * ip6_route_output(struct net *net, struct sock *sk,
 
 EXPORT_SYMBOL(ip6_route_output);
 
-int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl)
+struct dst_entry *ip6_dst_blackhole(struct net *net, struct dst_entry *dst_orig)
 {
-	struct rt6_info *ort = (struct rt6_info *) *dstp;
-	struct rt6_info *rt = (struct rt6_info *)
-		dst_alloc(&ip6_dst_blackhole_ops, 1);
+	struct rt6_info *rt = dst_alloc(&ip6_dst_blackhole_ops, 1);
+	struct rt6_info *ort = (struct rt6_info *) dst_orig;
 	struct dst_entry *new = NULL;
 
 	if (rt) {
@@ -905,9 +904,8 @@ int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl
 		dst_free(new);
 	}
 
-	dst_release(*dstp);
-	*dstp = new;
-	return new ? 0 : -ENOMEM;
+	dst_release(dst_orig);
+	return new ? new : ERR_PTR(-ENOMEM);
 }
 EXPORT_SYMBOL_GPL(ip6_dst_blackhole);
 
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 8/8] xfrm: Handle blackhole route creation via afinfo.
From: David Miller @ 2011-03-01 23:11 UTC (permalink / raw)
  To: netdev


That way we don't have to potentially do this in every xfrm_lookup()
caller.

Signed-off-by: David S. Miller <davem@davemloft.net>
---
 include/net/dst.h       |    8 --------
 include/net/ipv6.h      |    4 ++--
 include/net/route.h     |    1 +
 include/net/xfrm.h      |    1 +
 net/ipv4/route.c        |   20 +++++++-------------
 net/ipv4/xfrm4_policy.c |    1 +
 net/ipv6/ip6_output.c   |   32 ++++++++++----------------------
 net/ipv6/route.c        |    3 +--
 net/ipv6/xfrm6_policy.c |    1 +
 net/xfrm/xfrm_policy.c  |   46 ++++++++++++++++++++++++++--------------------
 10 files changed, 50 insertions(+), 67 deletions(-)

diff --git a/include/net/dst.h b/include/net/dst.h
index 15d67c8..8948452 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -432,17 +432,9 @@ static inline int xfrm_lookup(struct net *net, struct dst_entry **dst_p,
 {
 	return 0;
 } 
-static inline int __xfrm_lookup(struct net *net, struct dst_entry **dst_p,
-				const struct flowi *fl, struct sock *sk,
-				int flags)
-{
-	return 0;
-}
 #else
 extern int xfrm_lookup(struct net *net, struct dst_entry **dst_p,
 		       const struct flowi *fl, struct sock *sk, int flags);
-extern int __xfrm_lookup(struct net *net, struct dst_entry **dst_p,
-			 const struct flowi *fl, struct sock *sk, int flags);
 #endif
 #endif
 
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 5d125c1..d6d077d 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -520,8 +520,8 @@ extern struct dst_entry *	ip6_sk_dst_lookup_flow(struct sock *sk,
 						       struct flowi *fl,
 						       const struct in6_addr *final_dst,
 						       bool can_sleep);
-extern struct dst_entry *	ip6_dst_blackhole(struct net *net,
-						  struct dst_entry *orig_dst);
+extern struct dst_entry *	ip6_blackhole_route(struct net *net,
+						    struct dst_entry *orig_dst);
 
 /*
  *	skb processing functions
diff --git a/include/net/route.h b/include/net/route.h
index 923e670..707cfc8 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -121,6 +121,7 @@ extern void		rt_cache_flush_batch(struct net *net);
 extern int		__ip_route_output_key(struct net *, struct rtable **, const struct flowi *flp);
 extern int		ip_route_output_key(struct net *, struct rtable **, struct flowi *flp);
 extern int		ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk);
+extern struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig);
 
 extern int ip_route_input_common(struct sk_buff *skb, __be32 dst, __be32 src,
 				 u8 tos, struct net_device *devin, bool noref);
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index efded23..d5dcf39 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -280,6 +280,7 @@ struct xfrm_policy_afinfo {
 	int			(*fill_dst)(struct xfrm_dst *xdst,
 					    struct net_device *dev,
 					    const struct flowi *fl);
+	struct dst_entry	*(*blackhole_route)(struct net *net, struct dst_entry *orig);
 };
 
 extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 23d2050..e24e4cf 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2675,12 +2675,10 @@ static struct dst_ops ipv4_dst_blackhole_ops = {
 	.update_pmtu		=	ipv4_rt_blackhole_update_pmtu,
 };
 
-
-static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi *flp)
+struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig)
 {
-	struct rtable *ort = *rp;
-	struct rtable *rt = (struct rtable *)
-		dst_alloc(&ipv4_dst_blackhole_ops, 1);
+	struct rtable *rt = dst_alloc(&ipv4_dst_blackhole_ops, 1);
+	struct rtable *ort = (struct rtable *) dst_orig;
 
 	if (rt) {
 		struct dst_entry *new = &rt->dst;
@@ -2714,9 +2712,9 @@ static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi
 		dst_free(new);
 	}
 
-	dst_release(&(*rp)->dst);
-	*rp = rt;
-	return rt ? 0 : -ENOMEM;
+	dst_release(dst_orig);
+
+	return rt ? &rt->dst : ERR_PTR(-ENOMEM);
 }
 
 int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
@@ -2732,11 +2730,7 @@ int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
 			flp->fl4_src = (*rp)->rt_src;
 		if (!flp->fl4_dst)
 			flp->fl4_dst = (*rp)->rt_dst;
-		err = __xfrm_lookup(net, (struct dst_entry **)rp, flp, sk, 0);
-		if (err == -EREMOTE)
-			err = ipv4_dst_blackhole(net, rp, flp);
-
-		return err;
+		return xfrm_lookup(net, (struct dst_entry **)rp, flp, sk, 0);
 	}
 
 	return 0;
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 63aa88e..5f0f058 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -234,6 +234,7 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
 	.get_tos =		xfrm4_get_tos,
 	.init_path =		xfrm4_init_path,
 	.fill_dst =		xfrm4_fill_dst,
+	.blackhole_route =	ipv4_blackhole_route,
 };
 
 #ifdef CONFIG_SYSCTL
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index ac16f3b..35a4ad9 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1025,18 +1025,12 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi *fl,
 		return ERR_PTR(err);
 	if (final_dst)
 		ipv6_addr_copy(&fl->fl6_dst, final_dst);
-	if (can_sleep) {
+	if (can_sleep)
 		fl->flags |= FLOWI_FLAG_CAN_SLEEP;
-		err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
-		if (err == -EREMOTE)
-			return ip6_dst_blackhole(sock_net(sk), dst);
-		if (err)
-			return ERR_PTR(err);
-	} else {
-		err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
-		if (err)
-			return ERR_PTR(err);
-	}
+
+	err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
+	if (err)
+		return ERR_PTR(err);
 	return dst;
 }
 EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow);
@@ -1070,18 +1064,12 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi *fl,
 		return ERR_PTR(err);
 	if (final_dst)
 		ipv6_addr_copy(&fl->fl6_dst, final_dst);
-	if (can_sleep) {
+	if (can_sleep)
 		fl->flags |= FLOWI_FLAG_CAN_SLEEP;
-		err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
-		if (err == -EREMOTE)
-			return ip6_dst_blackhole(sock_net(sk), dst);
-		if (err)
-			return ERR_PTR(err);
-	} else {
-		err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
-		if (err)
-			return ERR_PTR(err);
-	}
+
+	err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
+	if (err)
+		return ERR_PTR(err);
 	return dst;
 }
 EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index cf6fdea..053a92e 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -870,7 +870,7 @@ struct dst_entry * ip6_route_output(struct net *net, struct sock *sk,
 
 EXPORT_SYMBOL(ip6_route_output);
 
-struct dst_entry *ip6_dst_blackhole(struct net *net, struct dst_entry *dst_orig)
+struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
 {
 	struct rt6_info *rt = dst_alloc(&ip6_dst_blackhole_ops, 1);
 	struct rt6_info *ort = (struct rt6_info *) dst_orig;
@@ -907,7 +907,6 @@ struct dst_entry *ip6_dst_blackhole(struct net *net, struct dst_entry *dst_orig)
 	dst_release(dst_orig);
 	return new ? new : ERR_PTR(-ENOMEM);
 }
-EXPORT_SYMBOL_GPL(ip6_dst_blackhole);
 
 /*
  *	Destination cache support functions
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index c128ca1..48ce496 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -274,6 +274,7 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
 	.get_tos =		xfrm6_get_tos,
 	.init_path =		xfrm6_init_path,
 	.fill_dst =		xfrm6_fill_dst,
+	.blackhole_route =	ip6_blackhole_route,
 };
 
 static int __init xfrm6_policy_init(void)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index f4c7467..0248afa 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1735,14 +1735,31 @@ error:
 	return ERR_PTR(err);
 }
 
+static struct dst_entry *make_blackhole(struct net *net, u16 family,
+					struct dst_entry *dst_orig)
+{
+	struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
+	struct dst_entry *ret;
+
+	if (!afinfo) {
+		dst_release(dst_orig);
+		ret = ERR_PTR(-EINVAL);
+	} else {
+		ret = afinfo->blackhole_route(net, dst_orig);
+	}
+	xfrm_policy_put_afinfo(afinfo);
+
+	return ret;
+}
+
 /* Main function: finds/creates a bundle for given flow.
  *
  * At the moment we eat a raw IP route. Mostly to speed up lookups
  * on interfaces with disabled IPsec.
  */
-int __xfrm_lookup(struct net *net, struct dst_entry **dst_p,
-		  const struct flowi *fl,
-		  struct sock *sk, int flags)
+int xfrm_lookup(struct net *net, struct dst_entry **dst_p,
+		const struct flowi *fl,
+		struct sock *sk, int flags)
 {
 	struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
 	struct flow_cache_object *flo;
@@ -1829,7 +1846,12 @@ restart:
 			dst_release(dst);
 			xfrm_pols_put(pols, drop_pols);
 			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
-			return -EREMOTE;
+
+			dst = make_blackhole(net, family, dst_orig);
+			if (IS_ERR(dst))
+				return PTR_ERR(dst);
+			*dst_p = dst;
+			return 0;
 		}
 		if (fl->flags & FLOWI_FLAG_CAN_SLEEP) {
 			DECLARE_WAITQUEUE(wait, current);
@@ -1895,22 +1917,6 @@ dropdst:
 	xfrm_pols_put(pols, drop_pols);
 	return err;
 }
-EXPORT_SYMBOL(__xfrm_lookup);
-
-int xfrm_lookup(struct net *net, struct dst_entry **dst_p,
-		const struct flowi *fl,
-		struct sock *sk, int flags)
-{
-	int err = __xfrm_lookup(net, dst_p, fl, sk, flags);
-
-	if (err == -EREMOTE) {
-		dst_release(*dst_p);
-		*dst_p = NULL;
-		err = -EAGAIN;
-	}
-
-	return err;
-}
 EXPORT_SYMBOL(xfrm_lookup);
 
 static inline int
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 5/7] x25: remove the BKL
From: Arnd Bergmann @ 2011-03-01 23:13 UTC (permalink / raw)
  To: linux-kernel
  Cc: Arnd Bergmann, Andrew Hendry, linux-x25, netdev, Eric Dumazet
In-Reply-To: <1299021191-17961-1-git-send-email-arnd@arndb.de>

This replaces all instances of lock_kernel in x25
with lock_sock, taking care to release the socket
lock around sleeping functions (sock_alloc_send_skb
and skb_recv_datagram). It is not clear whether
this is a correct solution, but it seem to be what
other protocols do in the same situation.

Includes a fix suggested by Eric Dumazet.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Andrew Hendry <andrew.hendry@gmail.com>
Cc: linux-x25@vger.kernel.org
Cc: netdev@vger.kernel.org
Cc: Eric Dumazet <eric.dumazet@gmail.com>
---
 net/x25/Kconfig   |    1 -
 net/x25/af_x25.c  |   58 ++++++++++++++++------------------------------------
 net/x25/x25_out.c |    7 ++++-
 3 files changed, 23 insertions(+), 43 deletions(-)

diff --git a/net/x25/Kconfig b/net/x25/Kconfig
index 2196e55..e6759c9 100644
--- a/net/x25/Kconfig
+++ b/net/x25/Kconfig
@@ -5,7 +5,6 @@
 config X25
 	tristate "CCITT X.25 Packet Layer (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
-	depends on BKL # should be fixable
 	---help---
 	  X.25 is a set of standardized network protocols, similar in scope to
 	  frame relay; the one physical line from your box to the X.25 network
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index ad96ee9..4680b1e 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -40,7 +40,6 @@
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/timer.h>
 #include <linux/string.h>
 #include <linux/net.h>
@@ -432,15 +431,6 @@ void x25_destroy_socket_from_timer(struct sock *sk)
 	sock_put(sk);
 }
 
-static void x25_destroy_socket(struct sock *sk)
-{
-	sock_hold(sk);
-	lock_sock(sk);
-	__x25_destroy_socket(sk);
-	release_sock(sk);
-	sock_put(sk);
-}
-
 /*
  *	Handling for system calls applied via the various interfaces to a
  *	X.25 socket object.
@@ -647,18 +637,19 @@ static int x25_release(struct socket *sock)
 	struct sock *sk = sock->sk;
 	struct x25_sock *x25;
 
-	lock_kernel();
 	if (!sk)
-		goto out;
+		return 0;
 
 	x25 = x25_sk(sk);
 
+	sock_hold(sk);
+	lock_sock(sk);
 	switch (x25->state) {
 
 		case X25_STATE_0:
 		case X25_STATE_2:
 			x25_disconnect(sk, 0, 0, 0);
-			x25_destroy_socket(sk);
+			__x25_destroy_socket(sk);
 			goto out;
 
 		case X25_STATE_1:
@@ -678,7 +669,8 @@ static int x25_release(struct socket *sock)
 
 	sock_orphan(sk);
 out:
-	unlock_kernel();
+	release_sock(sk);
+	sock_put(sk);
 	return 0;
 }
 
@@ -1085,7 +1077,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
 	size_t size;
 	int qbit = 0, rc = -EINVAL;
 
-	lock_kernel();
+	lock_sock(sk);
 	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_OOB|MSG_EOR|MSG_CMSG_COMPAT))
 		goto out;
 
@@ -1148,7 +1140,9 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
 
 	size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN;
 
+	release_sock(sk);
 	skb = sock_alloc_send_skb(sk, size, noblock, &rc);
+	lock_sock(sk);
 	if (!skb)
 		goto out;
 	X25_SKB_CB(skb)->flags = msg->msg_flags;
@@ -1231,26 +1225,10 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
 			len++;
 	}
 
-	/*
-	 * lock_sock() is currently only used to serialize this x25_kick()
-	 * against input-driven x25_kick() calls. It currently only blocks
-	 * incoming packets for this socket and does not protect against
-	 * any other socket state changes and is not called from anywhere
-	 * else. As x25_kick() cannot block and as long as all socket
-	 * operations are BKL-wrapped, we don't need take to care about
-	 * purging the backlog queue in x25_release().
-	 *
-	 * Using lock_sock() to protect all socket operations entirely
-	 * (and making the whole x25 stack SMP aware) unfortunately would
-	 * require major changes to {send,recv}msg and skb allocation methods.
-	 * -> 2.5 ;)
-	 */
-	lock_sock(sk);
 	x25_kick(sk);
-	release_sock(sk);
 	rc = len;
 out:
-	unlock_kernel();
+	release_sock(sk);
 	return rc;
 out_kfree_skb:
 	kfree_skb(skb);
@@ -1271,7 +1249,7 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
 	unsigned char *asmptr;
 	int rc = -ENOTCONN;
 
-	lock_kernel();
+	lock_sock(sk);
 	/*
 	 * This works for seqpacket too. The receiver has ordered the queue for
 	 * us! We do one quick check first though
@@ -1300,8 +1278,10 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
 		msg->msg_flags |= MSG_OOB;
 	} else {
 		/* Now we can treat all alike */
+		release_sock(sk);
 		skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
 					flags & MSG_DONTWAIT, &rc);
+		lock_sock(sk);
 		if (!skb)
 			goto out;
 
@@ -1338,14 +1318,12 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
 
 	msg->msg_namelen = sizeof(struct sockaddr_x25);
 
-	lock_sock(sk);
 	x25_check_rbuf(sk);
-	release_sock(sk);
 	rc = copied;
 out_free_dgram:
 	skb_free_datagram(sk, skb);
 out:
-	unlock_kernel();
+	release_sock(sk);
 	return rc;
 }
 
@@ -1581,18 +1559,18 @@ out_cud_release:
 
 		case SIOCX25CALLACCPTAPPRV: {
 			rc = -EINVAL;
-			lock_kernel();
+			lock_sock(sk);
 			if (sk->sk_state != TCP_CLOSE)
 				break;
 			clear_bit(X25_ACCPT_APPRV_FLAG, &x25->flags);
-			unlock_kernel();
+			release_sock(sk);
 			rc = 0;
 			break;
 		}
 
 		case SIOCX25SENDCALLACCPT:  {
 			rc = -EINVAL;
-			lock_kernel();
+			lock_sock(sk);
 			if (sk->sk_state != TCP_ESTABLISHED)
 				break;
 			/* must call accptapprv above */
@@ -1600,7 +1578,7 @@ out_cud_release:
 				break;
 			x25_write_internal(sk, X25_CALL_ACCEPTED);
 			x25->state = X25_STATE_3;
-			unlock_kernel();
+			release_sock(sk);
 			rc = 0;
 			break;
 		}
diff --git a/net/x25/x25_out.c b/net/x25/x25_out.c
index d00649f..0144271 100644
--- a/net/x25/x25_out.c
+++ b/net/x25/x25_out.c
@@ -68,8 +68,11 @@ int x25_output(struct sock *sk, struct sk_buff *skb)
 		frontlen = skb_headroom(skb);
 
 		while (skb->len > 0) {
-			if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len,
-							noblock, &err)) == NULL){
+			release_sock(sk);
+			skbn = sock_alloc_send_skb(sk, frontlen + max_len,
+						   noblock, &err);
+			lock_sock(sk);
+			if (!skbn) {
 				if (err == -EWOULDBLOCK && noblock){
 					kfree_skb(skb);
 					return sent;
-- 
1.7.1

^ permalink raw reply related


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