From 5ca8caff03b2d6940d572238608bd91128b6a39a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 23 Nov 2008 23:24:32 -0800 Subject: [PATCH] --- yaml --- r: 122111 b: refs/heads/master c: 1f87e235e6fb92c2968b52b9191de04f1aff8e77 h: refs/heads/master i: 122109: da88fafff9d379ff24c0df86f218ff9a72c84b28 122107: 37c20c1fd63c3ee1284bcdf3923a5d3c75b20e31 122103: e52806d2fbe0bba1080ebce80e0fedcd2fc1d290 122095: b8f31dfffd97a36431a0e35a191dc7c15c306795 122079: 979dd2ae7c2a07c4a0bb4508ed54927e26f1a435 122047: ad15cc65405231694a45932998f82759ebbc9787 121983: 52baa544882154647a13f0510d2d893c4cf11b7f 121855: 189b7f72aa64eecf1b3ee4b8652d4973b4cdeb92 v: v3 --- [refs] | 2 +- trunk/include/linux/etherdevice.h | 42 +++++++++++++++++++++++++++++++ trunk/net/ethernet/eth.c | 6 ++--- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/[refs] b/[refs] index c9699c8c68fa..8aa1a3a746ee 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 70eb1bfd52e97120eddf9b5aaabfe1ecdf4eb663 +refs/heads/master: 1f87e235e6fb92c2968b52b9191de04f1aff8e77 diff --git a/trunk/include/linux/etherdevice.h b/trunk/include/linux/etherdevice.h index 0e5e97060034..1cb0f0b90926 100644 --- a/trunk/include/linux/etherdevice.h +++ b/trunk/include/linux/etherdevice.h @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef __KERNEL__ extern __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev); @@ -140,6 +141,47 @@ static inline unsigned compare_ether_addr(const u8 *addr1, const u8 *addr2) BUILD_BUG_ON(ETH_ALEN != 6); return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0; } + +static inline unsigned long zap_last_2bytes(unsigned long value) +{ +#ifdef __BIG_ENDIAN + return value >> 16; +#else + return value << 16; +#endif +} + +/** + * compare_ether_addr_64bits - Compare two Ethernet addresses + * @addr1: Pointer to an array of 8 bytes + * @addr2: Pointer to an other array of 8 bytes + * + * Compare two ethernet addresses, returns 0 if equal. + * Same result than "memcmp(addr1, addr2, ETH_ALEN)" but without conditional + * branches, and possibly long word memory accesses on CPU allowing cheap + * unaligned memory reads. + * arrays = { byte1, byte2, byte3, byte4, byte6, byte7, pad1, pad2} + * + * Please note that alignment of addr1 & addr2 is only guaranted to be 16 bits. + */ + +static inline unsigned compare_ether_addr_64bits(const u8 addr1[6+2], + const u8 addr2[6+2]) +{ +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS + unsigned long fold = ((*(unsigned long *)addr1) ^ + (*(unsigned long *)addr2)); + + if (sizeof(fold) == 8) + return zap_last_2bytes(fold) != 0; + + fold |= zap_last_2bytes((*(unsigned long *)(addr1 + 4)) ^ + (*(unsigned long *)(addr2 + 4))); + return fold != 0; +#else + return compare_ether_addr(addr1, addr2); +#endif +} #endif /* __KERNEL__ */ #endif /* _LINUX_ETHERDEVICE_H */ diff --git a/trunk/net/ethernet/eth.c b/trunk/net/ethernet/eth.c index a87a171d9914..280352aba403 100644 --- a/trunk/net/ethernet/eth.c +++ b/trunk/net/ethernet/eth.c @@ -165,8 +165,8 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) skb_pull(skb, ETH_HLEN); eth = eth_hdr(skb); - if (is_multicast_ether_addr(eth->h_dest)) { - if (!compare_ether_addr(eth->h_dest, dev->broadcast)) + if (unlikely(is_multicast_ether_addr(eth->h_dest))) { + if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast)) skb->pkt_type = PACKET_BROADCAST; else skb->pkt_type = PACKET_MULTICAST; @@ -181,7 +181,7 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) */ else if (1 /*dev->flags&IFF_PROMISC */ ) { - if (unlikely(compare_ether_addr(eth->h_dest, dev->dev_addr))) + if (unlikely(compare_ether_addr_64bits(eth->h_dest, dev->dev_addr))) skb->pkt_type = PACKET_OTHERHOST; }