net: use skb_flow_dissect() in __skb_get_rxhash()

No functional changes.

This uses the code we factorized in skb_flow_dissect()

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Eric Dumazet 2011-11-28 05:23:23 +00:00 committed by David S. Miller
parent 0744dd00c1
commit 4504b8613b
1 changed files with 14 additions and 111 deletions

View File

@ -133,11 +133,9 @@
#include <linux/pci.h>
#include <linux/inetdevice.h>
#include <linux/cpu_rmap.h>
#include <linux/if_tunnel.h>
#include <linux/if_pppox.h>
#include <linux/ppp_defs.h>
#include <linux/net_tstamp.h>
#include <linux/jump_label.h>
#include <net/flow_keys.h>
#include "net-sysfs.h"
@ -2598,123 +2596,28 @@ static inline void ____napi_schedule(struct softnet_data *sd,
*/
void __skb_get_rxhash(struct sk_buff *skb)
{
int nhoff, hash = 0, poff;
const struct ipv6hdr *ip6;
const struct iphdr *ip;
const struct vlan_hdr *vlan;
u8 ip_proto;
u32 addr1, addr2;
u16 proto;
union {
u32 v32;
u16 v16[2];
} ports;
struct flow_keys keys;
u32 hash;
nhoff = skb_network_offset(skb);
proto = skb->protocol;
if (!skb_flow_dissect(skb, &keys))
return;
again:
switch (proto) {
case __constant_htons(ETH_P_IP):
ip:
if (!pskb_may_pull(skb, sizeof(*ip) + nhoff))
goto done;
ip = (const struct iphdr *) (skb->data + nhoff);
if (ip_is_fragment(ip))
ip_proto = 0;
else
ip_proto = ip->protocol;
addr1 = (__force u32) ip->saddr;
addr2 = (__force u32) ip->daddr;
nhoff += ip->ihl * 4;
break;
case __constant_htons(ETH_P_IPV6):
ipv6:
if (!pskb_may_pull(skb, sizeof(*ip6) + nhoff))
goto done;
ip6 = (const struct ipv6hdr *) (skb->data + nhoff);
ip_proto = ip6->nexthdr;
addr1 = (__force u32) ip6->saddr.s6_addr32[3];
addr2 = (__force u32) ip6->daddr.s6_addr32[3];
nhoff += 40;
break;
case __constant_htons(ETH_P_8021Q):
if (!pskb_may_pull(skb, sizeof(*vlan) + nhoff))
goto done;
vlan = (const struct vlan_hdr *) (skb->data + nhoff);
proto = vlan->h_vlan_encapsulated_proto;
nhoff += sizeof(*vlan);
goto again;
case __constant_htons(ETH_P_PPP_SES):
if (!pskb_may_pull(skb, PPPOE_SES_HLEN + nhoff))
goto done;
proto = *((__be16 *) (skb->data + nhoff +
sizeof(struct pppoe_hdr)));
nhoff += PPPOE_SES_HLEN;
switch (proto) {
case __constant_htons(PPP_IP):
goto ip;
case __constant_htons(PPP_IPV6):
goto ipv6;
default:
goto done;
}
default:
goto done;
}
switch (ip_proto) {
case IPPROTO_GRE:
if (pskb_may_pull(skb, nhoff + 16)) {
u8 *h = skb->data + nhoff;
__be16 flags = *(__be16 *)h;
/*
* Only look inside GRE if version zero and no
* routing
*/
if (!(flags & (GRE_VERSION|GRE_ROUTING))) {
proto = *(__be16 *)(h + 2);
nhoff += 4;
if (flags & GRE_CSUM)
nhoff += 4;
if (flags & GRE_KEY)
nhoff += 4;
if (flags & GRE_SEQ)
nhoff += 4;
goto again;
}
}
break;
case IPPROTO_IPIP:
goto again;
default:
break;
}
ports.v32 = 0;
poff = proto_ports_offset(ip_proto);
if (poff >= 0) {
nhoff += poff;
if (pskb_may_pull(skb, nhoff + 4)) {
ports.v32 = * (__force u32 *) (skb->data + nhoff);
if (ports.v16[1] < ports.v16[0])
swap(ports.v16[0], ports.v16[1]);
skb->l4_rxhash = 1;
}
if (keys.ports) {
if ((__force u16)keys.port16[1] < (__force u16)keys.port16[0])
swap(keys.port16[0], keys.port16[1]);
skb->l4_rxhash = 1;
}
/* get a consistent hash (same value on both flow directions) */
if (addr2 < addr1)
swap(addr1, addr2);
if ((__force u32)keys.dst < (__force u32)keys.src)
swap(keys.dst, keys.src);
hash = jhash_3words(addr1, addr2, ports.v32, hashrnd);
hash = jhash_3words((__force u32)keys.dst,
(__force u32)keys.src,
(__force u32)keys.ports, hashrnd);
if (!hash)
hash = 1;
done:
skb->rxhash = hash;
}
EXPORT_SYMBOL(__skb_get_rxhash);