netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next] bonding: remove packet cloning in recv_probe()
@ 2012-06-12  5:23 Eric Dumazet
  2012-06-13  0:47 ` Jay Vosburgh
  0 siblings, 1 reply; 3+ messages in thread
From: Eric Dumazet @ 2012-06-12  5:23 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, Jay Vosburgh, Andy Gospodarek, Jiri Bohac,
	Nicolas de Pesloüan, Maciej Żenczykowski

From: Eric Dumazet <edumazet@google.com>

Cloning all packets in input path have a significant cost.

Use skb_header_pointer()/skb_copy_bits() instead of pskb_may_pull() so
that recv_probe handlers (bond_3ad_lacpdu_recv / bond_arp_rcv /
rlb_arp_recv ) dont touch input skb.

bond_handle_frame() can avoid the skb_clone()/dev_kfree_skb()

Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Jay Vosburgh <fubar@us.ibm.com>
Cc: Andy Gospodarek <andy@greyhouse.net>
Cc: Jiri Bohac <jbohac@suse.cz>
Cc: Nicolas de Pesloüan <nicolas.2p.debian@free.fr>
Cc: Maciej Żenczykowski <maze@google.com>
---
 drivers/net/bonding/bond_3ad.c  |   11 +++++---
 drivers/net/bonding/bond_3ad.h  |    4 +--
 drivers/net/bonding/bond_alb.c  |   20 ++++------------
 drivers/net/bonding/bond_main.c |   37 ++++++++++++++++--------------
 drivers/net/bonding/bonding.h   |    4 +--
 5 files changed, 36 insertions(+), 40 deletions(-)

diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 3463b46..3031e04 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2460,18 +2460,21 @@ out:
 	return NETDEV_TX_OK;
 }
 
-int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond,
-			  struct slave *slave)
+int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
+			 struct slave *slave)
 {
 	int ret = RX_HANDLER_ANOTHER;
+	struct lacpdu *lacpdu, _lacpdu;
+
 	if (skb->protocol != PKT_TYPE_LACPDU)
 		return ret;
 
-	if (!pskb_may_pull(skb, sizeof(struct lacpdu)))
+	lacpdu = skb_header_pointer(skb, 0, sizeof(_lacpdu), &_lacpdu);
+	if (!lacpdu)
 		return ret;
 
 	read_lock(&bond->lock);
-	ret = bond_3ad_rx_indication((struct lacpdu *) skb->data, slave, skb->len);
+	ret = bond_3ad_rx_indication(lacpdu, slave, skb->len);
 	read_unlock(&bond->lock);
 	return ret;
 }
diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h
index 5ee7e3c..0cfaa4a 100644
--- a/drivers/net/bonding/bond_3ad.h
+++ b/drivers/net/bonding/bond_3ad.h
@@ -274,8 +274,8 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave);
 void bond_3ad_handle_link_change(struct slave *slave, char link);
 int  bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info);
 int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev);
-int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond,
-			  struct slave *slave);
+int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
+			 struct slave *slave);
 int bond_3ad_set_carrier(struct bonding *bond);
 void bond_3ad_update_lacp_rate(struct bonding *bond);
 #endif //__BOND_3AD_H__
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 0f59c15..ef3791a 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -342,27 +342,17 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
 	_unlock_rx_hashtbl_bh(bond);
 }
 
-static int rlb_arp_recv(struct sk_buff *skb, struct bonding *bond,
-			 struct slave *slave)
+static int rlb_arp_recv(const struct sk_buff *skb, struct bonding *bond,
+			struct slave *slave)
 {
-	struct arp_pkt *arp;
+	struct arp_pkt *arp, _arp;
 
 	if (skb->protocol != cpu_to_be16(ETH_P_ARP))
 		goto out;
 
-	arp = (struct arp_pkt *) skb->data;
-	if (!arp) {
-		pr_debug("Packet has no ARP data\n");
+	arp = skb_header_pointer(skb, 0, sizeof(_arp), &_arp);
+	if (!arp)
 		goto out;
-	}
-
-	if (!pskb_may_pull(skb, arp_hdr_len(bond->dev)))
-		goto out;
-
-	if (skb->len < sizeof(struct arp_pkt)) {
-		pr_debug("Packet is too small to be an ARP\n");
-		goto out;
-	}
 
 	if (arp->op_code == htons(ARPOP_REPLY)) {
 		/* update rx hash table for this ARP */
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 2ee8cf9..9e2301e 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1444,8 +1444,8 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
 	struct sk_buff *skb = *pskb;
 	struct slave *slave;
 	struct bonding *bond;
-	int (*recv_probe)(struct sk_buff *, struct bonding *,
-				struct slave *);
+	int (*recv_probe)(const struct sk_buff *, struct bonding *,
+			  struct slave *);
 	int ret = RX_HANDLER_ANOTHER;
 
 	skb = skb_share_check(skb, GFP_ATOMIC);
@@ -1462,15 +1462,10 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
 
 	recv_probe = ACCESS_ONCE(bond->recv_probe);
 	if (recv_probe) {
-		struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
-
-		if (likely(nskb)) {
-			ret = recv_probe(nskb, bond, slave);
-			dev_kfree_skb(nskb);
-			if (ret == RX_HANDLER_CONSUMED) {
-				consume_skb(skb);
-				return ret;
-			}
+		ret = recv_probe(skb, bond, slave);
+		if (ret == RX_HANDLER_CONSUMED) {
+			consume_skb(skb);
+			return ret;
 		}
 	}
 
@@ -2737,25 +2732,31 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32
 	}
 }
 
-static int bond_arp_rcv(struct sk_buff *skb, struct bonding *bond,
-			 struct slave *slave)
+static int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
+			struct slave *slave)
 {
-	struct arphdr *arp;
+	struct arphdr *arp = (struct arphdr *)skb->data;
 	unsigned char *arp_ptr;
 	__be32 sip, tip;
+	int alen;
 
 	if (skb->protocol != __cpu_to_be16(ETH_P_ARP))
 		return RX_HANDLER_ANOTHER;
 
 	read_lock(&bond->lock);
+	alen = arp_hdr_len(bond->dev);
 
 	pr_debug("bond_arp_rcv: bond %s skb->dev %s\n",
 		 bond->dev->name, skb->dev->name);
 
-	if (!pskb_may_pull(skb, arp_hdr_len(bond->dev)))
-		goto out_unlock;
+	if (alen > skb_headlen(skb)) {
+		arp = kmalloc(alen, GFP_ATOMIC);
+		if (!arp)
+			goto out_unlock;
+		if (skb_copy_bits(skb, 0, arp, alen) < 0)
+			goto out_unlock;
+	}
 
-	arp = arp_hdr(skb);
 	if (arp->ar_hln != bond->dev->addr_len ||
 	    skb->pkt_type == PACKET_OTHERHOST ||
 	    skb->pkt_type == PACKET_LOOPBACK ||
@@ -2790,6 +2791,8 @@ static int bond_arp_rcv(struct sk_buff *skb, struct bonding *bond,
 
 out_unlock:
 	read_unlock(&bond->lock);
+	if (arp != (struct arphdr *)skb->data)
+		kfree(arp);
 	return RX_HANDLER_ANOTHER;
 }
 
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 4581aa5..f8af2fc 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -218,8 +218,8 @@ struct bonding {
 	struct   slave *primary_slave;
 	bool     force_primary;
 	s32      slave_cnt; /* never change this value outside the attach/detach wrappers */
-	int     (*recv_probe)(struct sk_buff *, struct bonding *,
-			       struct slave *);
+	int     (*recv_probe)(const struct sk_buff *, struct bonding *,
+			      struct slave *);
 	rwlock_t lock;
 	rwlock_t curr_slave_lock;
 	u8	 send_peer_notif;

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH net-next] bonding: remove packet cloning in recv_probe()
  2012-06-12  5:23 [PATCH net-next] bonding: remove packet cloning in recv_probe() Eric Dumazet
@ 2012-06-13  0:47 ` Jay Vosburgh
  2012-06-13  1:52   ` David Miller
  0 siblings, 1 reply; 3+ messages in thread
From: Jay Vosburgh @ 2012-06-13  0:47 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David Miller, netdev, Andy Gospodarek, Jiri Bohac,
	Nicolas de =?ISO-8859-1?Q?Peslo=FCan?=,
	Maciej =?UTF-8?Q?=C5=BBenczykowski?=

Eric Dumazet <eric.dumazet@gmail.com> wrote:

>From: Eric Dumazet <edumazet@google.com>
>
>Cloning all packets in input path have a significant cost.
>
>Use skb_header_pointer()/skb_copy_bits() instead of pskb_may_pull() so
>that recv_probe handlers (bond_3ad_lacpdu_recv / bond_arp_rcv /
>rlb_arp_recv ) dont touch input skb.
>
>bond_handle_frame() can avoid the skb_clone()/dev_kfree_skb()
>
>Signed-off-by: Eric Dumazet <edumazet@google.com>
>Cc: Jay Vosburgh <fubar@us.ibm.com>
>Cc: Andy Gospodarek <andy@greyhouse.net>
>Cc: Jiri Bohac <jbohac@suse.cz>
>Cc: Nicolas de Pesloüan <nicolas.2p.debian@free.fr>
>Cc: Maciej Żenczykowski <maze@google.com>

	This looks really good to me.

	-J

Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>


>---
> drivers/net/bonding/bond_3ad.c  |   11 +++++---
> drivers/net/bonding/bond_3ad.h  |    4 +--
> drivers/net/bonding/bond_alb.c  |   20 ++++------------
> drivers/net/bonding/bond_main.c |   37 ++++++++++++++++--------------
> drivers/net/bonding/bonding.h   |    4 +--
> 5 files changed, 36 insertions(+), 40 deletions(-)
>
>diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
>index 3463b46..3031e04 100644
>--- a/drivers/net/bonding/bond_3ad.c
>+++ b/drivers/net/bonding/bond_3ad.c
>@@ -2460,18 +2460,21 @@ out:
> 	return NETDEV_TX_OK;
> }
>
>-int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond,
>-			  struct slave *slave)
>+int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
>+			 struct slave *slave)
> {
> 	int ret = RX_HANDLER_ANOTHER;
>+	struct lacpdu *lacpdu, _lacpdu;
>+
> 	if (skb->protocol != PKT_TYPE_LACPDU)
> 		return ret;
>
>-	if (!pskb_may_pull(skb, sizeof(struct lacpdu)))
>+	lacpdu = skb_header_pointer(skb, 0, sizeof(_lacpdu), &_lacpdu);
>+	if (!lacpdu)
> 		return ret;
>
> 	read_lock(&bond->lock);
>-	ret = bond_3ad_rx_indication((struct lacpdu *) skb->data, slave, skb->len);
>+	ret = bond_3ad_rx_indication(lacpdu, slave, skb->len);
> 	read_unlock(&bond->lock);
> 	return ret;
> }
>diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h
>index 5ee7e3c..0cfaa4a 100644
>--- a/drivers/net/bonding/bond_3ad.h
>+++ b/drivers/net/bonding/bond_3ad.h
>@@ -274,8 +274,8 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave);
> void bond_3ad_handle_link_change(struct slave *slave, char link);
> int  bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info);
> int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev);
>-int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond,
>-			  struct slave *slave);
>+int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
>+			 struct slave *slave);
> int bond_3ad_set_carrier(struct bonding *bond);
> void bond_3ad_update_lacp_rate(struct bonding *bond);
> #endif //__BOND_3AD_H__
>diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
>index 0f59c15..ef3791a 100644
>--- a/drivers/net/bonding/bond_alb.c
>+++ b/drivers/net/bonding/bond_alb.c
>@@ -342,27 +342,17 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
> 	_unlock_rx_hashtbl_bh(bond);
> }
>
>-static int rlb_arp_recv(struct sk_buff *skb, struct bonding *bond,
>-			 struct slave *slave)
>+static int rlb_arp_recv(const struct sk_buff *skb, struct bonding *bond,
>+			struct slave *slave)
> {
>-	struct arp_pkt *arp;
>+	struct arp_pkt *arp, _arp;
>
> 	if (skb->protocol != cpu_to_be16(ETH_P_ARP))
> 		goto out;
>
>-	arp = (struct arp_pkt *) skb->data;
>-	if (!arp) {
>-		pr_debug("Packet has no ARP data\n");
>+	arp = skb_header_pointer(skb, 0, sizeof(_arp), &_arp);
>+	if (!arp)
> 		goto out;
>-	}
>-
>-	if (!pskb_may_pull(skb, arp_hdr_len(bond->dev)))
>-		goto out;
>-
>-	if (skb->len < sizeof(struct arp_pkt)) {
>-		pr_debug("Packet is too small to be an ARP\n");
>-		goto out;
>-	}
>
> 	if (arp->op_code == htons(ARPOP_REPLY)) {
> 		/* update rx hash table for this ARP */
>diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
>index 2ee8cf9..9e2301e 100644
>--- a/drivers/net/bonding/bond_main.c
>+++ b/drivers/net/bonding/bond_main.c
>@@ -1444,8 +1444,8 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
> 	struct sk_buff *skb = *pskb;
> 	struct slave *slave;
> 	struct bonding *bond;
>-	int (*recv_probe)(struct sk_buff *, struct bonding *,
>-				struct slave *);
>+	int (*recv_probe)(const struct sk_buff *, struct bonding *,
>+			  struct slave *);
> 	int ret = RX_HANDLER_ANOTHER;
>
> 	skb = skb_share_check(skb, GFP_ATOMIC);
>@@ -1462,15 +1462,10 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
>
> 	recv_probe = ACCESS_ONCE(bond->recv_probe);
> 	if (recv_probe) {
>-		struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
>-
>-		if (likely(nskb)) {
>-			ret = recv_probe(nskb, bond, slave);
>-			dev_kfree_skb(nskb);
>-			if (ret == RX_HANDLER_CONSUMED) {
>-				consume_skb(skb);
>-				return ret;
>-			}
>+		ret = recv_probe(skb, bond, slave);
>+		if (ret == RX_HANDLER_CONSUMED) {
>+			consume_skb(skb);
>+			return ret;
> 		}
> 	}
>
>@@ -2737,25 +2732,31 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32
> 	}
> }
>
>-static int bond_arp_rcv(struct sk_buff *skb, struct bonding *bond,
>-			 struct slave *slave)
>+static int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
>+			struct slave *slave)
> {
>-	struct arphdr *arp;
>+	struct arphdr *arp = (struct arphdr *)skb->data;
> 	unsigned char *arp_ptr;
> 	__be32 sip, tip;
>+	int alen;
>
> 	if (skb->protocol != __cpu_to_be16(ETH_P_ARP))
> 		return RX_HANDLER_ANOTHER;
>
> 	read_lock(&bond->lock);
>+	alen = arp_hdr_len(bond->dev);
>
> 	pr_debug("bond_arp_rcv: bond %s skb->dev %s\n",
> 		 bond->dev->name, skb->dev->name);
>
>-	if (!pskb_may_pull(skb, arp_hdr_len(bond->dev)))
>-		goto out_unlock;
>+	if (alen > skb_headlen(skb)) {
>+		arp = kmalloc(alen, GFP_ATOMIC);
>+		if (!arp)
>+			goto out_unlock;
>+		if (skb_copy_bits(skb, 0, arp, alen) < 0)
>+			goto out_unlock;
>+	}
>
>-	arp = arp_hdr(skb);
> 	if (arp->ar_hln != bond->dev->addr_len ||
> 	    skb->pkt_type == PACKET_OTHERHOST ||
> 	    skb->pkt_type == PACKET_LOOPBACK ||
>@@ -2790,6 +2791,8 @@ static int bond_arp_rcv(struct sk_buff *skb, struct bonding *bond,
>
> out_unlock:
> 	read_unlock(&bond->lock);
>+	if (arp != (struct arphdr *)skb->data)
>+		kfree(arp);
> 	return RX_HANDLER_ANOTHER;
> }
>
>diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
>index 4581aa5..f8af2fc 100644
>--- a/drivers/net/bonding/bonding.h
>+++ b/drivers/net/bonding/bonding.h
>@@ -218,8 +218,8 @@ struct bonding {
> 	struct   slave *primary_slave;
> 	bool     force_primary;
> 	s32      slave_cnt; /* never change this value outside the attach/detach wrappers */
>-	int     (*recv_probe)(struct sk_buff *, struct bonding *,
>-			       struct slave *);
>+	int     (*recv_probe)(const struct sk_buff *, struct bonding *,
>+			      struct slave *);
> 	rwlock_t lock;
> 	rwlock_t curr_slave_lock;
> 	u8	 send_peer_notif;
>
>

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH net-next] bonding: remove packet cloning in recv_probe()
  2012-06-13  0:47 ` Jay Vosburgh
@ 2012-06-13  1:52   ` David Miller
  0 siblings, 0 replies; 3+ messages in thread
From: David Miller @ 2012-06-13  1:52 UTC (permalink / raw)
  To: fubar; +Cc: eric.dumazet, netdev, andy, jbohac, nicolas.2p.debian, maze

From: Jay Vosburgh <fubar@us.ibm.com>
Date: Tue, 12 Jun 2012 17:47:59 -0700

> Eric Dumazet <eric.dumazet@gmail.com> wrote:
> 
>>From: Eric Dumazet <edumazet@google.com>
>>
>>Cloning all packets in input path have a significant cost.
>>
>>Use skb_header_pointer()/skb_copy_bits() instead of pskb_may_pull() so
>>that recv_probe handlers (bond_3ad_lacpdu_recv / bond_arp_rcv /
>>rlb_arp_recv ) dont touch input skb.
>>
>>bond_handle_frame() can avoid the skb_clone()/dev_kfree_skb()
>>
>>Signed-off-by: Eric Dumazet <edumazet@google.com>
>>Cc: Jay Vosburgh <fubar@us.ibm.com>
>>Cc: Andy Gospodarek <andy@greyhouse.net>
>>Cc: Jiri Bohac <jbohac@suse.cz>
>>Cc: Nicolas de Pesloüan <nicolas.2p.debian@free.fr>
>>Cc: Maciej Żenczykowski <maze@google.com>
> 
> 	This looks really good to me.
> 
> 	-J
> 
> Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>

Applied.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2012-06-13  1:52 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-06-12  5:23 [PATCH net-next] bonding: remove packet cloning in recv_probe() Eric Dumazet
2012-06-13  0:47 ` Jay Vosburgh
2012-06-13  1:52   ` David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).