diff options
author | Tom Herbert <therbert@google.com> | 2015-02-24 12:17:31 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-02-27 16:00:01 -0500 |
commit | 723b8e460d87e957f251dc5764f4ab86af6ab44e (patch) | |
tree | 2453607eb05e7cdf3913fedfe55599641c6a66b1 | |
parent | fed0a159c8c5e453d79d6a73897c576efea0a8a5 (diff) |
udp: In udp_flow_src_port use random hash value if skb_get_hash fails
In the unlikely event that skb_get_hash is unable to deduce a hash
in udp_flow_src_port we use a consistent random value instead.
This is specified in GRE/UDP draft section 3.2.1:
https://tools.ietf.org/html/draft-ietf-tsvwg-gre-in-udp-encap-04
Signed-off-by: Tom Herbert <therbert@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/udp.h | 21 | ||||
-rw-r--r-- | net/ipv4/udp.c | 10 |
2 files changed, 25 insertions, 6 deletions
diff --git a/include/net/udp.h b/include/net/udp.h index 07f9b70962f6..32d8d9f07f76 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, | |||
194 | int (*)(const struct sock *, const struct sock *), | 194 | int (*)(const struct sock *, const struct sock *), |
195 | unsigned int hash2_nulladdr); | 195 | unsigned int hash2_nulladdr); |
196 | 196 | ||
197 | u32 udp_flow_hashrnd(void); | ||
198 | |||
197 | static inline __be16 udp_flow_src_port(struct net *net, struct sk_buff *skb, | 199 | static inline __be16 udp_flow_src_port(struct net *net, struct sk_buff *skb, |
198 | int min, int max, bool use_eth) | 200 | int min, int max, bool use_eth) |
199 | { | 201 | { |
@@ -205,12 +207,19 @@ static inline __be16 udp_flow_src_port(struct net *net, struct sk_buff *skb, | |||
205 | } | 207 | } |
206 | 208 | ||
207 | hash = skb_get_hash(skb); | 209 | hash = skb_get_hash(skb); |
208 | if (unlikely(!hash) && use_eth) { | 210 | if (unlikely(!hash)) { |
209 | /* Can't find a normal hash, caller has indicated an Ethernet | 211 | if (use_eth) { |
210 | * packet so use that to compute a hash. | 212 | /* Can't find a normal hash, caller has indicated an |
211 | */ | 213 | * Ethernet packet so use that to compute a hash. |
212 | hash = jhash(skb->data, 2 * ETH_ALEN, | 214 | */ |
213 | (__force u32) skb->protocol); | 215 | hash = jhash(skb->data, 2 * ETH_ALEN, |
216 | (__force u32) skb->protocol); | ||
217 | } else { | ||
218 | /* Can't derive any sort of hash for the packet, set | ||
219 | * to some consistent random value. | ||
220 | */ | ||
221 | hash = udp_flow_hashrnd(); | ||
222 | } | ||
214 | } | 223 | } |
215 | 224 | ||
216 | /* Since this is being sent on the wire obfuscate hash a bit | 225 | /* 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 97ef1f8b7be8..0224f930c613 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) | |||
2525 | } | 2525 | } |
2526 | } | 2526 | } |
2527 | 2527 | ||
2528 | u32 udp_flow_hashrnd(void) | ||
2529 | { | ||
2530 | static u32 hashrnd __read_mostly; | ||
2531 | |||
2532 | net_get_random_once(&hashrnd, sizeof(hashrnd)); | ||
2533 | |||
2534 | return hashrnd; | ||
2535 | } | ||
2536 | EXPORT_SYMBOL(udp_flow_hashrnd); | ||
2537 | |||
2528 | void __init udp_init(void) | 2538 | void __init udp_init(void) |
2529 | { | 2539 | { |
2530 | unsigned long limit; | 2540 | unsigned long limit; |