No subject


Sat Oct 12 03:57:18 UTC 2013


l4-rxhash. Therefore compat skb_get_rxhash() is not used on
kernel 3.8 or new.

Signed-off-by: Pravin B Shelar <pshelar at nicira.com>
Reviewed-by: Thomas Graf <tgraf at redhat.com>
---
v1-v2:
Removed jump-lable compat code due to backport complexity.
---
 datapath/linux/compat/flow_dissector.c       |   54 ++++++++++++++++----------
 datapath/linux/compat/include/linux/net.h    |   23 +++++++++++
 datapath/linux/compat/include/linux/skbuff.h |    8 +++-
 datapath/linux/compat/utils.c                |   21 ++++++++++
 4 files changed, 83 insertions(+), 23 deletions(-)

diff --git a/datapath/linux/compat/flow_dissector.c b/datapath/linux/compat/flow_dissector.c
index 8592ca9..f176f9a 100644
--- a/datapath/linux/compat/flow_dissector.c
+++ b/datapath/linux/compat/flow_dissector.c
@@ -19,7 +19,7 @@
  */
 
 #include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/if_vlan.h>
@@ -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));
 }
 
+__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,33 +178,30 @@ 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)
@@ -206,11 +220,9 @@ 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;
 
diff --git a/datapath/linux/compat/include/linux/net.h b/datapath/linux/compat/include/linux/net.h
index 5665e2e..ae226ea 100644
--- a/datapath/linux/compat/include/linux/net.h
+++ b/datapath/linux/compat/include/linux/net.h
@@ -2,6 +2,7 @@
 #define __LINUX_NET_WRAPPER_H 1
 
 #include_next <linux/net.h>
+#include <linux/atomic.h>
 
 #ifndef net_ratelimited_function
 #define net_ratelimited_function(function, ...)			\
@@ -28,4 +29,26 @@ do {								\
 	net_ratelimited_function(pr_debug, fmt, ##__VA_ARGS__)
 #endif
 
+#ifndef net_get_random_once
+bool __net_get_random_once(void *buf, int nbytes, bool *done,
+			   atomic_t *done_key);
+
+#define ___NET_RANDOM_STATIC_KEY_INIT	ATOMIC_INIT(0)
+
+
+#define net_get_random_once(buf, nbytes)			\
+({								\
+	bool ___ret = false;					\
+	static bool ___done = false;				\
+	static atomic_t ___done_key =				\
+			___NET_RANDOM_STATIC_KEY_INIT;		\
+	if (!atomic_read(&___done_key))				\
+	        ___ret = __net_get_random_once(buf,		\
+					       nbytes,		\
+					       &___done,	\
+					       &___done_key);	\
+	___ret;							\
+})
+#endif
+
 #endif
diff --git a/datapath/linux/compat/include/linux/skbuff.h b/datapath/linux/compat/include/linux/skbuff.h
index 9868a98..3af3ddc 100644
--- a/datapath/linux/compat/include/linux/skbuff.h
+++ b/datapath/linux/compat/include/linux/skbuff.h
@@ -213,12 +213,16 @@ static inline int skb_unclone(struct sk_buff *skb, gfp_t pri)
 }
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
+#define __skb_get_rxhash rpl__skb_get_rxhash
+#define skb_get_rxhash rpl_skb_get_rxhash
+
 extern u32 __skb_get_rxhash(struct sk_buff *skb);
 static inline __u32 skb_get_rxhash(struct sk_buff *skb)
 {
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34)
-	if (!skb->rxhash)
+	if (skb->rxhash)
+		return skb->rxhash;
 #endif
 	return __skb_get_rxhash(skb);
 }
diff --git a/datapath/linux/compat/utils.c b/datapath/linux/compat/utils.c
index 844d372..dc4df2a 100644
--- a/datapath/linux/compat/utils.c
+++ b/datapath/linux/compat/utils.c
@@ -37,3 +37,24 @@ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
 					csum_unfold(*sum)));
 }
 #endif
+
+bool __net_get_random_once(void *buf, int nbytes, bool *done,
+			   atomic_t *done_key)
+{
+	static DEFINE_SPINLOCK(lock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&lock, flags);
+	if (*done) {
+		spin_unlock_irqrestore(&lock, flags);
+		return false;
+	}
+
+	get_random_bytes(buf, nbytes);
+	*done = true;
+	spin_unlock_irqrestore(&lock, flags);
+
+	atomic_set(done_key, 1);
+
+	return true;
+}
-- 
1.7.1



More information about the dev mailing list