diff --git a/include/net/udp.h b/include/net/udp.h index 07f9b70962f64f0a7e80fe1ebbc81996be2d4567..32d8d9f07f76d9c54e5a4cdd122f586a8653008a 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -194,6 +194,8 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, int (*)(const struct sock *, const struct sock *), unsigned int hash2_nulladdr); +u32 udp_flow_hashrnd(void); + static inline __be16 udp_flow_src_port(struct net *net, struct sk_buff *skb, int min, int max, bool use_eth) { @@ -205,12 +207,19 @@ static inline __be16 udp_flow_src_port(struct net *net, struct sk_buff *skb, } hash = skb_get_hash(skb); - if (unlikely(!hash) && use_eth) { - /* Can't find a normal hash, caller has indicated an Ethernet - * packet so use that to compute a hash. - */ - hash = jhash(skb->data, 2 * ETH_ALEN, - (__force u32) skb->protocol); + if (unlikely(!hash)) { + if (use_eth) { + /* Can't find a normal hash, caller has indicated an + * Ethernet packet so use that to compute a hash. + */ + hash = jhash(skb->data, 2 * ETH_ALEN, + (__force u32) skb->protocol); + } else { + /* Can't derive any sort of hash for the packet, set + * to some consistent random value. + */ + hash = udp_flow_hashrnd(); + } } /* Since this is being sent on the wire obfuscate hash a bit diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 97ef1f8b7be81ed7d06c599b4158db0507afde44..0224f930c61373bd2dcacc472685100b3267b0b2 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2525,6 +2525,16 @@ void __init udp_table_init(struct udp_table *table, const char *name) } } +u32 udp_flow_hashrnd(void) +{ + static u32 hashrnd __read_mostly; + + net_get_random_once(&hashrnd, sizeof(hashrnd)); + + return hashrnd; +} +EXPORT_SYMBOL(udp_flow_hashrnd); + void __init udp_init(void) { unsigned long limit;