summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-05-04 04:30:36 +0200
committerDavid S. Miller <davem@davemloft.net>2015-05-04 04:30:36 +0200
commit7a852021a4ec2978c5d58d1904eeb90a8b2805fe (patch)
tree3f5fe450644b92d062c9e6f52a56e9e50bcec8f5
parentipv6: Flow label state ranges (diff)
parentetherdev: Use skb->data to retrieve Ethernet header instead of eth_hdr (diff)
downloadlinux-7a852021a4ec2978c5d58d1904eeb90a8b2805fe.tar.xz
linux-7a852021a4ec2978c5d58d1904eeb90a8b2805fe.zip
Merge branch 'eth_type_trans'
Alexander Duyck says: ==================== A few minor clean-ups to eth_type_trans This series addresses a few minor issues I found in eth_type_trans that that allow us to gain back something like 3 or more cycles per packet. The first change is to drop the byte swap since it isn't necessary. On x86 we could just check the first byte and compare that against the upper 8 bits of the Ethertype to determine if we are dealing with a size value or not. The second makes it so that the value we read in to test for multicast can be used for the address comparison. This allows us to avoid a second read of the destination address. The final change is to avoid some unneeded instructions in computing the Ethernet header pointer. When we start the call the Ethernet header is at skb->data, so we just use that rather than computing mac_header, and then adding that back to skb->head. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/etherdevice.h24
-rw-r--r--net/ethernet/eth.c7
2 files changed, 27 insertions, 4 deletions
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index 606563ef8a72..c4a10f991fe0 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -110,7 +110,29 @@ static inline bool is_zero_ether_addr(const u8 *addr)
*/
static inline bool is_multicast_ether_addr(const u8 *addr)
{
- return 0x01 & addr[0];
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
+ u32 a = *(const u32 *)addr;
+#else
+ u16 a = *(const u16 *)addr;
+#endif
+#ifdef __BIG_ENDIAN
+ return 0x01 & (a >> ((sizeof(a) * 8) - 8));
+#else
+ return 0x01 & a;
+#endif
+}
+
+static inline bool is_multicast_ether_addr_64bits(const u8 addr[6+2])
+{
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
+#ifdef __BIG_ENDIAN
+ return 0x01 & ((*(const u64 *)addr) >> 56);
+#else
+ return 0x01 & (*(const u64 *)addr);
+#endif
+#else
+ return is_multicast_ether_addr(addr);
+#endif
}
/**
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index f3bad41d725f..314e4c5a5a5e 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -156,10 +156,11 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
skb->dev = dev;
skb_reset_mac_header(skb);
+
+ eth = (struct ethhdr *)skb->data;
skb_pull_inline(skb, ETH_HLEN);
- eth = eth_hdr(skb);
- if (unlikely(is_multicast_ether_addr(eth->h_dest))) {
+ if (unlikely(is_multicast_ether_addr_64bits(eth->h_dest))) {
if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast))
skb->pkt_type = PACKET_BROADCAST;
else
@@ -178,7 +179,7 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
if (unlikely(netdev_uses_dsa(dev)))
return htons(ETH_P_XDSA);
- if (likely(ntohs(eth->h_proto) >= ETH_P_802_3_MIN))
+ if (likely((eth->h_proto & htons(0xFF00)) >= htons(ETH_P_802_3_MIN)))
return eth->h_proto;
/*