Commit 4504b861 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

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: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0744dd00
Loading
Loading
Loading
Loading
+14 −111
Original line number Diff line number Diff line
@@ -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;

	nhoff = skb_network_offset(skb);
	proto = skb->protocol;

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;
	struct flow_keys keys;
	u32 hash;

			/*
			 * 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;
	}
	if (!skb_flow_dissect(skb, &keys))
		return;

	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]);
	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);