udp: In udp_flow_src_port use random hash value if skb_get_hash fails
authorTom Herbert <therbert@google.com>
Tue, 24 Feb 2015 17:17:31 +0000 (09:17 -0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 27 Feb 2015 21:00:01 +0000 (16:00 -0500)
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>
include/net/udp.h
net/ipv4/udp.c

index 07f9b70962f64f0a7e80fe1ebbc81996be2d4567..32d8d9f07f76d9c54e5a4cdd122f586a8653008a 100644 (file)
@@ -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
index 97ef1f8b7be81ed7d06c599b4158db0507afde44..0224f930c61373bd2dcacc472685100b3267b0b2 100644 (file)
@@ -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;