diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-04-19 17:56:38 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-04-20 04:18:06 -0400 |
commit | b249dcb82d327e419d3cb45773b146ebb5faf419 (patch) | |
tree | 3424eac7e208c03a49ad182685f1ba3c836628b8 /net/core/dev.c | |
parent | e36fa2f7e92f25aab2e3d787dcfe3590817f19d3 (diff) |
rps: consistent rxhash
In case we compute a software skb->rxhash, we can generate a consistent
hash : Its value will be the same in both flow directions.
This helps some workloads, like conntracking, since the same state needs
to be accessed in both directions.
tbench + RFS + this patch gives better results than tbench with default
kernel configuration (no RPS, no RFS)
Also fixed some sparse warnings.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/dev.c')
-rw-r--r-- | net/core/dev.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 7f5755b0a57c..0d78e0454a6d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -1974,7 +1974,7 @@ u16 skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb) | |||
1974 | if (skb->sk && skb->sk->sk_hash) | 1974 | if (skb->sk && skb->sk->sk_hash) |
1975 | hash = skb->sk->sk_hash; | 1975 | hash = skb->sk->sk_hash; |
1976 | else | 1976 | else |
1977 | hash = skb->protocol; | 1977 | hash = (__force u16) skb->protocol; |
1978 | 1978 | ||
1979 | hash = jhash_1word(hash, hashrnd); | 1979 | hash = jhash_1word(hash, hashrnd); |
1980 | 1980 | ||
@@ -2253,8 +2253,8 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb, | |||
2253 | 2253 | ||
2254 | ip = (struct iphdr *) skb->data; | 2254 | ip = (struct iphdr *) skb->data; |
2255 | ip_proto = ip->protocol; | 2255 | ip_proto = ip->protocol; |
2256 | addr1 = ip->saddr; | 2256 | addr1 = (__force u32) ip->saddr; |
2257 | addr2 = ip->daddr; | 2257 | addr2 = (__force u32) ip->daddr; |
2258 | ihl = ip->ihl; | 2258 | ihl = ip->ihl; |
2259 | break; | 2259 | break; |
2260 | case __constant_htons(ETH_P_IPV6): | 2260 | case __constant_htons(ETH_P_IPV6): |
@@ -2263,8 +2263,8 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb, | |||
2263 | 2263 | ||
2264 | ip6 = (struct ipv6hdr *) skb->data; | 2264 | ip6 = (struct ipv6hdr *) skb->data; |
2265 | ip_proto = ip6->nexthdr; | 2265 | ip_proto = ip6->nexthdr; |
2266 | addr1 = ip6->saddr.s6_addr32[3]; | 2266 | addr1 = (__force u32) ip6->saddr.s6_addr32[3]; |
2267 | addr2 = ip6->daddr.s6_addr32[3]; | 2267 | addr2 = (__force u32) ip6->daddr.s6_addr32[3]; |
2268 | ihl = (40 >> 2); | 2268 | ihl = (40 >> 2); |
2269 | break; | 2269 | break; |
2270 | default: | 2270 | default: |
@@ -2279,14 +2279,25 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb, | |||
2279 | case IPPROTO_AH: | 2279 | case IPPROTO_AH: |
2280 | case IPPROTO_SCTP: | 2280 | case IPPROTO_SCTP: |
2281 | case IPPROTO_UDPLITE: | 2281 | case IPPROTO_UDPLITE: |
2282 | if (pskb_may_pull(skb, (ihl * 4) + 4)) | 2282 | if (pskb_may_pull(skb, (ihl * 4) + 4)) { |
2283 | ports = *((u32 *) (skb->data + (ihl * 4))); | 2283 | __be16 *hports = (__be16 *) (skb->data + (ihl * 4)); |
2284 | u32 sport, dport; | ||
2285 | |||
2286 | sport = (__force u16) hports[0]; | ||
2287 | dport = (__force u16) hports[1]; | ||
2288 | if (dport < sport) | ||
2289 | swap(sport, dport); | ||
2290 | ports = (sport << 16) + dport; | ||
2291 | } | ||
2284 | break; | 2292 | break; |
2285 | 2293 | ||
2286 | default: | 2294 | default: |
2287 | break; | 2295 | break; |
2288 | } | 2296 | } |
2289 | 2297 | ||
2298 | /* get a consistent hash (same value on both flow directions) */ | ||
2299 | if (addr2 < addr1) | ||
2300 | swap(addr1, addr2); | ||
2290 | skb->rxhash = jhash_3words(addr1, addr2, ports, hashrnd); | 2301 | skb->rxhash = jhash_3words(addr1, addr2, ports, hashrnd); |
2291 | if (!skb->rxhash) | 2302 | if (!skb->rxhash) |
2292 | skb->rxhash = 1; | 2303 | skb->rxhash = 1; |