diff options
author | David S. Miller <davem@davemloft.net> | 2008-07-21 12:48:06 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-07-21 13:10:48 -0400 |
commit | b6b2fed1f4802b8fcc9d7548a8f785225d38f9a3 (patch) | |
tree | eebdc34112d617524b762c585b79b2eaab3386ae /net/core/dev.c | |
parent | c3ee84163e5bc0dc2e1ccf1d3fc412debca73bab (diff) |
net: Improve simple_tx_hash().
Based upon feedback from Eric Dumazet and Andi Kleen.
Cure several deficiencies in simple_tx_hash() by using
jhash + reciprocol multiply.
1) Eliminates expensive modulus operation.
2) Makes hash less attackable by using random seed.
3) Eliminates endianness hash distribution issues.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/dev.c')
-rw-r--r-- | net/core/dev.c | 34 |
1 files changed, 21 insertions, 13 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 2eed17bcb2dd..7e2d5274333f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -124,6 +124,8 @@ | |||
124 | #include <linux/ip.h> | 124 | #include <linux/ip.h> |
125 | #include <linux/ipv6.h> | 125 | #include <linux/ipv6.h> |
126 | #include <linux/in.h> | 126 | #include <linux/in.h> |
127 | #include <linux/jhash.h> | ||
128 | #include <linux/random.h> | ||
127 | 129 | ||
128 | #include "net-sysfs.h" | 130 | #include "net-sysfs.h" |
129 | 131 | ||
@@ -1668,34 +1670,37 @@ out_kfree_skb: | |||
1668 | * --BLG | 1670 | * --BLG |
1669 | */ | 1671 | */ |
1670 | 1672 | ||
1673 | static u32 simple_tx_hashrnd; | ||
1674 | static int simple_tx_hashrnd_initialized = 0; | ||
1675 | |||
1671 | static u16 simple_tx_hash(struct net_device *dev, struct sk_buff *skb) | 1676 | static u16 simple_tx_hash(struct net_device *dev, struct sk_buff *skb) |
1672 | { | 1677 | { |
1673 | u32 *addr, *ports, hash, ihl; | 1678 | u32 addr1, addr2, ports; |
1679 | u32 hash, ihl; | ||
1674 | u8 ip_proto; | 1680 | u8 ip_proto; |
1675 | int alen; | 1681 | |
1682 | if (unlikely(!simple_tx_hashrnd_initialized)) { | ||
1683 | get_random_bytes(&simple_tx_hashrnd, 4); | ||
1684 | simple_tx_hashrnd_initialized = 1; | ||
1685 | } | ||
1676 | 1686 | ||
1677 | switch (skb->protocol) { | 1687 | switch (skb->protocol) { |
1678 | case __constant_htons(ETH_P_IP): | 1688 | case __constant_htons(ETH_P_IP): |
1679 | ip_proto = ip_hdr(skb)->protocol; | 1689 | ip_proto = ip_hdr(skb)->protocol; |
1680 | addr = &ip_hdr(skb)->saddr; | 1690 | addr1 = ip_hdr(skb)->saddr; |
1691 | addr2 = ip_hdr(skb)->daddr; | ||
1681 | ihl = ip_hdr(skb)->ihl; | 1692 | ihl = ip_hdr(skb)->ihl; |
1682 | alen = 2; | ||
1683 | break; | 1693 | break; |
1684 | case __constant_htons(ETH_P_IPV6): | 1694 | case __constant_htons(ETH_P_IPV6): |
1685 | ip_proto = ipv6_hdr(skb)->nexthdr; | 1695 | ip_proto = ipv6_hdr(skb)->nexthdr; |
1686 | addr = &ipv6_hdr(skb)->saddr.s6_addr32[0]; | 1696 | addr1 = ipv6_hdr(skb)->saddr.s6_addr32[3]; |
1697 | addr2 = ipv6_hdr(skb)->daddr.s6_addr32[3]; | ||
1687 | ihl = (40 >> 2); | 1698 | ihl = (40 >> 2); |
1688 | alen = 8; | ||
1689 | break; | 1699 | break; |
1690 | default: | 1700 | default: |
1691 | return 0; | 1701 | return 0; |
1692 | } | 1702 | } |
1693 | 1703 | ||
1694 | ports = (u32 *) (skb_network_header(skb) + (ihl * 4)); | ||
1695 | |||
1696 | hash = 0; | ||
1697 | while (alen--) | ||
1698 | hash ^= *addr++; | ||
1699 | 1704 | ||
1700 | switch (ip_proto) { | 1705 | switch (ip_proto) { |
1701 | case IPPROTO_TCP: | 1706 | case IPPROTO_TCP: |
@@ -1705,14 +1710,17 @@ static u16 simple_tx_hash(struct net_device *dev, struct sk_buff *skb) | |||
1705 | case IPPROTO_AH: | 1710 | case IPPROTO_AH: |
1706 | case IPPROTO_SCTP: | 1711 | case IPPROTO_SCTP: |
1707 | case IPPROTO_UDPLITE: | 1712 | case IPPROTO_UDPLITE: |
1708 | hash ^= *ports; | 1713 | ports = *((u32 *) (skb_network_header(skb) + (ihl * 4))); |
1709 | break; | 1714 | break; |
1710 | 1715 | ||
1711 | default: | 1716 | default: |
1717 | ports = 0; | ||
1712 | break; | 1718 | break; |
1713 | } | 1719 | } |
1714 | 1720 | ||
1715 | return hash % dev->real_num_tx_queues; | 1721 | hash = jhash_3words(addr1, addr2, ports, simple_tx_hashrnd); |
1722 | |||
1723 | return (u16) (((u64) hash * dev->real_num_tx_queues) >> 32); | ||
1716 | } | 1724 | } |
1717 | 1725 | ||
1718 | static struct netdev_queue *dev_pick_tx(struct net_device *dev, | 1726 | static struct netdev_queue *dev_pick_tx(struct net_device *dev, |