aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/bonding
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2012-06-11 15:23:07 -0400
committerDavid S. Miller <davem@davemloft.net>2012-06-12 21:51:09 -0400
commitde063b7040dcd9fbc9a1847fa44f0af13e19d6de (patch)
treed828ad11df0863ae1594be4461bfdbcb5388c4a8 /drivers/net/bonding
parent072c0559e26bc35700b3a70dffc230f00d9262b8 (diff)
bonding: remove packet cloning in recv_probe()
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> Signed-off-by: Jay Vosburgh <fubar@us.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r--drivers/net/bonding/bond_3ad.c11
-rw-r--r--drivers/net/bonding/bond_3ad.h4
-rw-r--r--drivers/net/bonding/bond_alb.c20
-rw-r--r--drivers/net/bonding/bond_main.c37
-rw-r--r--drivers/net/bonding/bonding.h4
5 files changed, 36 insertions, 40 deletions
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 3463b469e657..3031e0413114 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2460,18 +2460,21 @@ out:
2460 return NETDEV_TX_OK; 2460 return NETDEV_TX_OK;
2461} 2461}
2462 2462
2463int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond, 2463int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
2464 struct slave *slave) 2464 struct slave *slave)
2465{ 2465{
2466 int ret = RX_HANDLER_ANOTHER; 2466 int ret = RX_HANDLER_ANOTHER;
2467 struct lacpdu *lacpdu, _lacpdu;
2468
2467 if (skb->protocol != PKT_TYPE_LACPDU) 2469 if (skb->protocol != PKT_TYPE_LACPDU)
2468 return ret; 2470 return ret;
2469 2471
2470 if (!pskb_may_pull(skb, sizeof(struct lacpdu))) 2472 lacpdu = skb_header_pointer(skb, 0, sizeof(_lacpdu), &_lacpdu);
2473 if (!lacpdu)
2471 return ret; 2474 return ret;
2472 2475
2473 read_lock(&bond->lock); 2476 read_lock(&bond->lock);
2474 ret = bond_3ad_rx_indication((struct lacpdu *) skb->data, slave, skb->len); 2477 ret = bond_3ad_rx_indication(lacpdu, slave, skb->len);
2475 read_unlock(&bond->lock); 2478 read_unlock(&bond->lock);
2476 return ret; 2479 return ret;
2477} 2480}
diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h
index 5ee7e3c45db7..0cfaa4afdece 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);
274void bond_3ad_handle_link_change(struct slave *slave, char link); 274void bond_3ad_handle_link_change(struct slave *slave, char link);
275int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info); 275int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info);
276int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev); 276int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev);
277int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond, 277int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
278 struct slave *slave); 278 struct slave *slave);
279int bond_3ad_set_carrier(struct bonding *bond); 279int bond_3ad_set_carrier(struct bonding *bond);
280void bond_3ad_update_lacp_rate(struct bonding *bond); 280void bond_3ad_update_lacp_rate(struct bonding *bond);
281#endif //__BOND_3AD_H__ 281#endif //__BOND_3AD_H__
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 0f59c1564e53..ef3791a09ad8 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)
342 _unlock_rx_hashtbl_bh(bond); 342 _unlock_rx_hashtbl_bh(bond);
343} 343}
344 344
345static int rlb_arp_recv(struct sk_buff *skb, struct bonding *bond, 345static int rlb_arp_recv(const struct sk_buff *skb, struct bonding *bond,
346 struct slave *slave) 346 struct slave *slave)
347{ 347{
348 struct arp_pkt *arp; 348 struct arp_pkt *arp, _arp;
349 349
350 if (skb->protocol != cpu_to_be16(ETH_P_ARP)) 350 if (skb->protocol != cpu_to_be16(ETH_P_ARP))
351 goto out; 351 goto out;
352 352
353 arp = (struct arp_pkt *) skb->data; 353 arp = skb_header_pointer(skb, 0, sizeof(_arp), &_arp);
354 if (!arp) { 354 if (!arp)
355 pr_debug("Packet has no ARP data\n");
356 goto out; 355 goto out;
357 }
358
359 if (!pskb_may_pull(skb, arp_hdr_len(bond->dev)))
360 goto out;
361
362 if (skb->len < sizeof(struct arp_pkt)) {
363 pr_debug("Packet is too small to be an ARP\n");
364 goto out;
365 }
366 356
367 if (arp->op_code == htons(ARPOP_REPLY)) { 357 if (arp->op_code == htons(ARPOP_REPLY)) {
368 /* update rx hash table for this ARP */ 358 /* update rx hash table for this ARP */
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 2ee8cf9e8a3b..9e2301eef386 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)
1444 struct sk_buff *skb = *pskb; 1444 struct sk_buff *skb = *pskb;
1445 struct slave *slave; 1445 struct slave *slave;
1446 struct bonding *bond; 1446 struct bonding *bond;
1447 int (*recv_probe)(struct sk_buff *, struct bonding *, 1447 int (*recv_probe)(const struct sk_buff *, struct bonding *,
1448 struct slave *); 1448 struct slave *);
1449 int ret = RX_HANDLER_ANOTHER; 1449 int ret = RX_HANDLER_ANOTHER;
1450 1450
1451 skb = skb_share_check(skb, GFP_ATOMIC); 1451 skb = skb_share_check(skb, GFP_ATOMIC);
@@ -1462,15 +1462,10 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
1462 1462
1463 recv_probe = ACCESS_ONCE(bond->recv_probe); 1463 recv_probe = ACCESS_ONCE(bond->recv_probe);
1464 if (recv_probe) { 1464 if (recv_probe) {
1465 struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC); 1465 ret = recv_probe(skb, bond, slave);
1466 1466 if (ret == RX_HANDLER_CONSUMED) {
1467 if (likely(nskb)) { 1467 consume_skb(skb);
1468 ret = recv_probe(nskb, bond, slave); 1468 return ret;
1469 dev_kfree_skb(nskb);
1470 if (ret == RX_HANDLER_CONSUMED) {
1471 consume_skb(skb);
1472 return ret;
1473 }
1474 } 1469 }
1475 } 1470 }
1476 1471
@@ -2737,25 +2732,31 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32
2737 } 2732 }
2738} 2733}
2739 2734
2740static int bond_arp_rcv(struct sk_buff *skb, struct bonding *bond, 2735static int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
2741 struct slave *slave) 2736 struct slave *slave)
2742{ 2737{
2743 struct arphdr *arp; 2738 struct arphdr *arp = (struct arphdr *)skb->data;
2744 unsigned char *arp_ptr; 2739 unsigned char *arp_ptr;
2745 __be32 sip, tip; 2740 __be32 sip, tip;
2741 int alen;
2746 2742
2747 if (skb->protocol != __cpu_to_be16(ETH_P_ARP)) 2743 if (skb->protocol != __cpu_to_be16(ETH_P_ARP))
2748 return RX_HANDLER_ANOTHER; 2744 return RX_HANDLER_ANOTHER;
2749 2745
2750 read_lock(&bond->lock); 2746 read_lock(&bond->lock);
2747 alen = arp_hdr_len(bond->dev);
2751 2748
2752 pr_debug("bond_arp_rcv: bond %s skb->dev %s\n", 2749 pr_debug("bond_arp_rcv: bond %s skb->dev %s\n",
2753 bond->dev->name, skb->dev->name); 2750 bond->dev->name, skb->dev->name);
2754 2751
2755 if (!pskb_may_pull(skb, arp_hdr_len(bond->dev))) 2752 if (alen > skb_headlen(skb)) {
2756 goto out_unlock; 2753 arp = kmalloc(alen, GFP_ATOMIC);
2754 if (!arp)
2755 goto out_unlock;
2756 if (skb_copy_bits(skb, 0, arp, alen) < 0)
2757 goto out_unlock;
2758 }
2757 2759
2758 arp = arp_hdr(skb);
2759 if (arp->ar_hln != bond->dev->addr_len || 2760 if (arp->ar_hln != bond->dev->addr_len ||
2760 skb->pkt_type == PACKET_OTHERHOST || 2761 skb->pkt_type == PACKET_OTHERHOST ||
2761 skb->pkt_type == PACKET_LOOPBACK || 2762 skb->pkt_type == PACKET_LOOPBACK ||
@@ -2790,6 +2791,8 @@ static int bond_arp_rcv(struct sk_buff *skb, struct bonding *bond,
2790 2791
2791out_unlock: 2792out_unlock:
2792 read_unlock(&bond->lock); 2793 read_unlock(&bond->lock);
2794 if (arp != (struct arphdr *)skb->data)
2795 kfree(arp);
2793 return RX_HANDLER_ANOTHER; 2796 return RX_HANDLER_ANOTHER;
2794} 2797}
2795 2798
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 4581aa5ccaba..f8af2fcd3d16 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -218,8 +218,8 @@ struct bonding {
218 struct slave *primary_slave; 218 struct slave *primary_slave;
219 bool force_primary; 219 bool force_primary;
220 s32 slave_cnt; /* never change this value outside the attach/detach wrappers */ 220 s32 slave_cnt; /* never change this value outside the attach/detach wrappers */
221 int (*recv_probe)(struct sk_buff *, struct bonding *, 221 int (*recv_probe)(const struct sk_buff *, struct bonding *,
222 struct slave *); 222 struct slave *);
223 rwlock_t lock; 223 rwlock_t lock;
224 rwlock_t curr_slave_lock; 224 rwlock_t curr_slave_lock;
225 u8 send_peer_notif; 225 u8 send_peer_notif;