X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=datapath%2Flinux%2Fcompat%2Fflow_dissector.c;h=ab60daa3b61c5f26c3c05090aa14f5a33a1b2637;hb=e2f3178f0582eda302bdc5629189b6a56d9fbcdd;hp=8592ca9fbc1a5cc8c9e89355294ba7378a04aa5d;hpb=1b7ee51f9d340aa6c9f6a5772f4e79cbfd17565d;p=sliver-openvswitch.git diff --git a/datapath/linux/compat/flow_dissector.c b/datapath/linux/compat/flow_dissector.c index 8592ca9fb..ab60daa3b 100644 --- a/datapath/linux/compat/flow_dissector.c +++ b/datapath/linux/compat/flow_dissector.c @@ -19,7 +19,7 @@ */ #include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0) #include #include #include @@ -46,9 +46,25 @@ static void iph_to_flow_copy_addrs(struct flow_keys *flow, const struct iphdr *i memcpy(&flow->src, &iph->saddr, sizeof(flow->src) + sizeof(flow->dst)); } +static __be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto) +{ + int poff = proto_ports_offset(ip_proto); + + if (poff >= 0) { + __be32 *ports, _ports; + + ports = skb_header_pointer(skb, thoff + poff, + sizeof(_ports), &_ports); + if (ports) + return *ports; + } + + return 0; +} + static bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow) { - int poff, nhoff = skb_network_offset(skb); + int nhoff = skb_network_offset(skb); u8 ip_proto; __be16 proto = skb->protocol; @@ -86,6 +102,7 @@ ipv6: nhoff += sizeof(struct ipv6hdr); break; } + case __constant_htons(ETH_P_8021AD): case __constant_htons(ETH_P_8021Q): { const struct vlan_hdr *vlan; struct vlan_hdr _vlan; @@ -161,36 +178,33 @@ ipv6: } case IPPROTO_IPIP: goto again; + case IPPROTO_IPV6: + proto = htons(ETH_P_IPV6); + goto ipv6; default: break; } flow->ip_proto = ip_proto; - poff = proto_ports_offset(ip_proto); - if (poff >= 0) { - __be32 *ports, _ports; - - nhoff += poff; - ports = skb_header_pointer(skb, nhoff, sizeof(_ports), &_ports); - if (ports) - flow->ports = *ports; - } - + flow->ports = skb_flow_get_ports(skb, nhoff, ip_proto); flow->thoff = (u16) nhoff; return true; } static u32 hashrnd __read_mostly; +static __always_inline void __flow_hash_secret_init(void) +{ + net_get_random_once(&hashrnd, sizeof(hashrnd)); +} -static void init_hashrnd(void) +static __always_inline u32 __flow_hash_3words(u32 a, u32 b, u32 c) { - if (likely(hashrnd)) - return; - get_random_bytes(&hashrnd, sizeof(hashrnd)); + __flow_hash_secret_init(); + return jhash_3words(a, b, c, hashrnd); } -u32 __skb_get_rxhash(struct sk_buff *skb) +u32 __skb_get_hash(struct sk_buff *skb) { struct flow_keys keys; u32 hash; @@ -206,15 +220,13 @@ u32 __skb_get_rxhash(struct sk_buff *skb) swap(keys.port16[0], keys.port16[1]); } - init_hashrnd(); - - hash = jhash_3words((__force u32)keys.dst, - (__force u32)keys.src, - (__force u32)keys.ports, hashrnd); + hash = __flow_hash_3words((__force u32)keys.dst, + (__force u32)keys.src, + (__force u32)keys.ports); if (!hash) hash = 1; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) +#ifdef HAVE_RXHASH skb->rxhash = hash; #endif return hash;