diff options
author | Eric Dumazet <edumazet@google.com> | 2012-06-11 15:23:07 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-06-12 21:51:09 -0400 |
commit | de063b7040dcd9fbc9a1847fa44f0af13e19d6de (patch) | |
tree | d828ad11df0863ae1594be4461bfdbcb5388c4a8 /drivers/net/bonding | |
parent | 072c0559e26bc35700b3a70dffc230f00d9262b8 (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.c | 11 | ||||
-rw-r--r-- | drivers/net/bonding/bond_3ad.h | 4 | ||||
-rw-r--r-- | drivers/net/bonding/bond_alb.c | 20 | ||||
-rw-r--r-- | drivers/net/bonding/bond_main.c | 37 | ||||
-rw-r--r-- | 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 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 | ||
2463 | int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond, | 2463 | int 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); | |||
274 | void bond_3ad_handle_link_change(struct slave *slave, char link); | 274 | void bond_3ad_handle_link_change(struct slave *slave, char link); |
275 | int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info); | 275 | int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info); |
276 | int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev); | 276 | int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev); |
277 | int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond, | 277 | int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond, |
278 | struct slave *slave); | 278 | struct slave *slave); |
279 | int bond_3ad_set_carrier(struct bonding *bond); | 279 | int bond_3ad_set_carrier(struct bonding *bond); |
280 | void bond_3ad_update_lacp_rate(struct bonding *bond); | 280 | void 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 | ||
345 | static int rlb_arp_recv(struct sk_buff *skb, struct bonding *bond, | 345 | static 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 | ||
2740 | static int bond_arp_rcv(struct sk_buff *skb, struct bonding *bond, | 2735 | static 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 | ||
2791 | out_unlock: | 2792 | out_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; |