Query on skb headroom and bridging ethernet and wlan

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]


Hello All,
	We have observed significant throughput drop on TX path on
embedded system when bridging packets from ethernet to wireless side.
Our drivers on ethernet and wireless are MV643XX and MWL8K, respectively.

We found that mac80211 end up calling ieee80211_skb_resize (from
net/mac80211/tx.c) for every data packet as the skb_headroom was few
bytes short than the actual requirement.

We are considering two possible solutions to the problem:
1. Use the scheme developed by Johannes and David.
2. Address the issue by tuning the required extra tx headroom in the mwl8k
wireless driver.

The scheme developed by Johannes and David is discussed at the thread started by
Johannes on "mac80211: assign needed_headroom/tailroom for netdevs".

Can be seen at
http://kerneltrap.com/mailarchive/linux-netdev/2008/5/4/1719104

In one of the reply, David Miller has proposed a solution for such cases; please
see http://lists.openwall.net/netdev/2008/05/05/133

For completeness I am adding David's patch after few modifications, mainly
replacing old variables with the updated ones to make compilation error free.

With the patch below and a change in ethernet driver to use netdev_alloc_skb, 
overhead of ieee80211_skb_resize can be avoided on our setup.

We would like to know, why is this patch (or something similar) not upstream?
Or, are there issues that are difficult to resolve?

Thanks
Yogesh Powar

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 0249fe7..1827ef0 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1193,6 +1193,7 @@ struct net_device {
 						 * use it if/when necessary, to
 						 * avoid dirtying this cache line.
 						 */
+	unsigned int rx_alloc_extra;
 
 	struct net_device	*master; /* Pointer to master device of a group,
 					  * which this device is member of.
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index ee64287..cb2a462 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -46,6 +46,23 @@ int br_dev_queue_push_xmit(struct sk_buff *skb)
 	    (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))) {
 		kfree_skb(skb);
 	} else {
+		unsigned int headroom = skb_headroom(skb);
+		unsigned int hh_len = LL_RESERVED_SPACE(skb->dev);
+
+		if (headroom < hh_len) {
+			struct net_device *in_dev;
+			unsigned int extra;
+
+			in_dev = __dev_get_by_index(dev_net(skb->dev), skb->skb_iif);
+
+			BUG_ON(!in_dev);
+
+			extra = hh_len - headroom;
+
+			if (extra > in_dev->rx_alloc_extra)
+				in_dev->rx_alloc_extra = extra;
+		}
+
 		skb_push(skb, ETH_HLEN);
 		dev_queue_xmit(skb);
 	}
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 801dd08..d9cbd4f 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -249,10 +249,11 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
 		unsigned int length, gfp_t gfp_mask)
 {
 	struct sk_buff *skb;
+	unsigned int extra = dev->rx_alloc_extra + NET_SKB_PAD;
 
-	skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, 0, NUMA_NO_NODE);
+	skb = __alloc_skb(length + extra, gfp_mask, 0, NUMA_NO_NODE);
 	if (likely(skb)) {
-		skb_reserve(skb, NET_SKB_PAD);
+		skb_reserve(skb, extra);
 		skb->dev = dev;
 	}
 	return skb;
-- 
--
To unsubscribe from this list: send the line "unsubscribe linux-net" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Netdev]     [Ethernet Bridging]     [Linux 802.1Q VLAN]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Git]     [Bugtraq]     [Photo]     [Yosemite]     [Yosemite News and Information]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux PCI]     [Linux Admin]     [Samba]     [Video 4 Linux]     [Linux Resources]

Add to Google