* [PATCH net-next 2/4] siphash: implement HalfSipHash1-3 for hash tables
From: Jason A. Donenfeld @ 2017-01-06 20:10 UTC (permalink / raw)
To: davem, netdev, linux-kernel; +Cc: Jason A. Donenfeld, Jean-Philippe Aumasson
In-Reply-To: <20170106201055.13765-1-Jason@zx2c4.com>
HalfSipHash, or hsiphash, is a shortened version of SipHash, which
generates 32-bit outputs using a weaker 64-bit key. It has *much* lower
security margins, and shouldn't be used for anything too sensitive, but
it could be used as a hashtable key function replacement, if the output
is never exposed, and if the security requirement is not too high.
The goal is to make this something that performance-critical jhash users
would be willing to use.
On 64-bit machines, HalfSipHash1-3 is slower than SipHash1-3, so we alias
SipHash1-3 to HalfSipHash1-3 on those systems.
64-bit x86_64:
[ 0.509409] test_siphash: SipHash2-4 cycles: 4049181
[ 0.510650] test_siphash: SipHash1-3 cycles: 2512884
[ 0.512205] test_siphash: HalfSipHash1-3 cycles: 3429920
[ 0.512904] test_siphash: JenkinsHash cycles: 978267
So, we map hsiphash() -> SipHash1-3
32-bit x86:
[ 0.509868] test_siphash: SipHash2-4 cycles: 14812892
[ 0.513601] test_siphash: SipHash1-3 cycles: 9510710
[ 0.515263] test_siphash: HalfSipHash1-3 cycles: 3856157
[ 0.515952] test_siphash: JenkinsHash cycles: 1148567
So, we map hsiphash() -> HalfSipHash1-3
hsiphash() is roughly 3 times slower than jhash(), but comes with a
considerable security improvement.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Cc: Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
---
Documentation/siphash.txt | 75 +++++++++++
include/linux/siphash.h | 56 +++++++-
lib/siphash.c | 318 +++++++++++++++++++++++++++++++++++++++++++++-
lib/test_siphash.c | 139 ++++++++++++++++----
4 files changed, 561 insertions(+), 27 deletions(-)
diff --git a/Documentation/siphash.txt b/Documentation/siphash.txt
index 39ff7f0438e7..f93c1d7104c4 100644
--- a/Documentation/siphash.txt
+++ b/Documentation/siphash.txt
@@ -77,3 +77,78 @@ Linux implements the "2-4" variant of SipHash.
Read the SipHash paper if you're interested in learning more:
https://131002.net/siphash/siphash.pdf
+
+
+~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
+
+HalfSipHash - SipHash's insecure younger cousin
+-----------------------------------------------
+Written by Jason A. Donenfeld <jason@zx2c4.com>
+
+On the off-chance that SipHash is not fast enough for your needs, you might be
+able to justify using HalfSipHash, a terrifying but potentially useful
+possibility. HalfSipHash cuts SipHash's rounds down from "2-4" to "1-3" and,
+even scarier, uses an easily brute-forcable 64-bit key (with a 32-bit output)
+instead of SipHash's 128-bit key. However, this may appeal to some
+high-performance `jhash` users.
+
+Danger!
+
+Do not ever use HalfSipHash except for as a hashtable key function, and only
+then when you can be absolutely certain that the outputs will never be
+transmitted out of the kernel. This is only remotely useful over `jhash` as a
+means of mitigating hashtable flooding denial of service attacks.
+
+1. Generating a key
+
+Keys should always be generated from a cryptographically secure source of
+random numbers, either using get_random_bytes or get_random_once:
+
+hsiphash_key_t key;
+get_random_bytes(key, sizeof(key));
+
+If you're not deriving your key from here, you're doing it wrong.
+
+2. Using the functions
+
+There are two variants of the function, one that takes a list of integers, and
+one that takes a buffer:
+
+u32 hsiphash(const void *data, size_t len, siphash_key_t key);
+
+And:
+
+u32 hsiphash_1u32(u32, hsiphash_key_t key);
+u32 hsiphash_2u32(u32, u32, hsiphash_key_t key);
+u32 hsiphash_3u32(u32, u32, u32, hsiphash_key_t key);
+u32 hsiphash_4u32(u32, u32, u32, u32, hsiphash_key_t key);
+
+If you pass the generic hsiphash function something of a constant length, it
+will constant fold at compile-time and automatically choose one of the
+optimized functions.
+
+3. Hashtable key function usage:
+
+struct some_hashtable {
+ DECLARE_HASHTABLE(hashtable, 8);
+ hsiphash_key_t key;
+};
+
+void init_hashtable(struct some_hashtable *table)
+{
+ get_random_bytes(table->key, sizeof(table->key));
+}
+
+static inline hlist_head *some_hashtable_bucket(struct some_hashtable *table, struct interesting_input *input)
+{
+ return &table->hashtable[hsiphash(input, sizeof(*input), table->key) & (HASH_SIZE(table->hashtable) - 1)];
+}
+
+You may then iterate like usual over the returned hash bucket.
+
+4. Performance
+
+HalfSipHash is roughly 3 times slower than JenkinsHash. For many replacements,
+this will not be a problem, as the hashtable lookup isn't the bottleneck. And
+in general, this is probably a good sacrifice to make for the security and DoS
+resistance of HalfSipHash.
diff --git a/include/linux/siphash.h b/include/linux/siphash.h
index 7aa666eb00d9..efab44c654f3 100644
--- a/include/linux/siphash.h
+++ b/include/linux/siphash.h
@@ -5,7 +5,9 @@
* SipHash: a fast short-input PRF
* https://131002.net/siphash/
*
- * This implementation is specifically for SipHash2-4.
+ * This implementation is specifically for SipHash2-4 for a secure PRF
+ * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for
+ * hashtables.
*/
#ifndef _LINUX_SIPHASH_H
@@ -76,4 +78,56 @@ static inline u64 siphash(const void *data, size_t len, const siphash_key_t key)
return ___siphash_aligned(data, len, key);
}
+#if BITS_PER_LONG == 64
+typedef siphash_key_t hsiphash_key_t;
+#define HSIPHASH_ALIGNMENT SIPHASH_ALIGNMENT
+#else
+typedef u32 hsiphash_key_t[2];
+#define HSIPHASH_ALIGNMENT __alignof__(u32)
+#endif
+
+u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t key);
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+u32 __hsiphash_unaligned(const void *data, size_t len, const hsiphash_key_t key);
+#endif
+
+u32 hsiphash_1u32(const u32 a, const hsiphash_key_t key);
+u32 hsiphash_2u32(const u32 a, const u32 b, const hsiphash_key_t key);
+u32 hsiphash_3u32(const u32 a, const u32 b, const u32 c,
+ const hsiphash_key_t key);
+u32 hsiphash_4u32(const u32 a, const u32 b, const u32 c, const u32 d,
+ const hsiphash_key_t key);
+
+static inline u32 ___hsiphash_aligned(const __le32 *data, size_t len, const hsiphash_key_t key)
+{
+ if (__builtin_constant_p(len) && len == 4)
+ return hsiphash_1u32(le32_to_cpu(data[0]), key);
+ if (__builtin_constant_p(len) && len == 8)
+ return hsiphash_2u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]),
+ key);
+ if (__builtin_constant_p(len) && len == 12)
+ return hsiphash_3u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]),
+ le32_to_cpu(data[2]), key);
+ if (__builtin_constant_p(len) && len == 16)
+ return hsiphash_4u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]),
+ le32_to_cpu(data[2]), le32_to_cpu(data[3]),
+ key);
+ return __hsiphash_aligned(data, len, key);
+}
+
+/**
+ * hsiphash - compute 32-bit hsiphash PRF value
+ * @data: buffer to hash
+ * @size: size of @data
+ * @key: the hsiphash key
+ */
+static inline u32 hsiphash(const void *data, size_t len, const hsiphash_key_t key)
+{
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+ if (!IS_ALIGNED((unsigned long)data, HSIPHASH_ALIGNMENT))
+ return __hsiphash_unaligned(data, len, key);
+#endif
+ return ___hsiphash_aligned(data, len, key);
+}
+
#endif /* _LINUX_SIPHASH_H */
diff --git a/lib/siphash.c b/lib/siphash.c
index ff2151313667..e2481226d96c 100644
--- a/lib/siphash.c
+++ b/lib/siphash.c
@@ -5,7 +5,9 @@
* SipHash: a fast short-input PRF
* https://131002.net/siphash/
*
- * This implementation is specifically for SipHash2-4.
+ * This implementation is specifically for SipHash2-4 for a secure PRF
+ * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for
+ * hashtables.
*/
#include <linux/siphash.h>
@@ -230,3 +232,317 @@ u64 siphash_3u32(const u32 first, const u32 second, const u32 third,
POSTAMBLE
}
EXPORT_SYMBOL(siphash_3u32);
+
+#if BITS_PER_LONG == 64
+/* Note that this HalfSipHash1-3 implementation on 64-bit
+ * isn't actually HalfSipHash1-3 but rather SipHash1-3. */
+
+#define HSIPROUND SIPROUND
+#define HPREAMBLE(len) PREAMBLE(len)
+#define HPOSTAMBLE \
+ v3 ^= b; \
+ HSIPROUND; \
+ v0 ^= b; \
+ v2 ^= 0xff; \
+ HSIPROUND; \
+ HSIPROUND; \
+ HSIPROUND; \
+ return (v0 ^ v1) ^ (v2 ^ v3);
+
+u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t key)
+{
+ const u8 *end = data + len - (len % sizeof(u64));
+ const u8 left = len & (sizeof(u64) - 1);
+ u64 m;
+ HPREAMBLE(len)
+ for (; data != end; data += sizeof(u64)) {
+ m = le64_to_cpup(data);
+ v3 ^= m;
+ HSIPROUND;
+ v0 ^= m;
+ }
+#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
+ if (left)
+ b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
+ bytemask_from_count(left)));
+#else
+ switch (left) {
+ case 7: b |= ((u64)end[6]) << 48;
+ case 6: b |= ((u64)end[5]) << 40;
+ case 5: b |= ((u64)end[4]) << 32;
+ case 4: b |= le32_to_cpup(data); break;
+ case 3: b |= ((u64)end[2]) << 16;
+ case 2: b |= le16_to_cpup(data); break;
+ case 1: b |= end[0];
+ }
+#endif
+ HPOSTAMBLE
+}
+EXPORT_SYMBOL(__hsiphash_aligned);
+
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+u32 __hsiphash_unaligned(const void *data, size_t len, const hsiphash_key_t key)
+{
+ const u8 *end = data + len - (len % sizeof(u64));
+ const u8 left = len & (sizeof(u64) - 1);
+ u64 m;
+ HPREAMBLE(len)
+ for (; data != end; data += sizeof(u64)) {
+ m = get_unaligned_le64(data);
+ v3 ^= m;
+ HSIPROUND;
+ v0 ^= m;
+ }
+#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
+ if (left)
+ b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
+ bytemask_from_count(left)));
+#else
+ switch (left) {
+ case 7: b |= ((u64)end[6]) << 48;
+ case 6: b |= ((u64)end[5]) << 40;
+ case 5: b |= ((u64)end[4]) << 32;
+ case 4: b |= get_unaligned_le32(end); break;
+ case 3: b |= ((u64)end[2]) << 16;
+ case 2: b |= get_unaligned_le16(end); break;
+ case 1: b |= end[0];
+ }
+#endif
+ HPOSTAMBLE
+}
+EXPORT_SYMBOL(__hsiphash_unaligned);
+#endif
+
+/**
+ * hsiphash_1u32 - compute 64-bit hsiphash PRF value of a u32
+ * @first: first u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_1u32(const u32 first, const hsiphash_key_t key)
+{
+ HPREAMBLE(4)
+ b |= first;
+ HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_1u32);
+
+/**
+ * hsiphash_2u32 - compute 32-bit hsiphash PRF value of 2 u32
+ * @first: first u32
+ * @second: second u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_2u32(const u32 first, const u32 second, const hsiphash_key_t key)
+{
+ u64 combined = (u64)second << 32 | first;
+ HPREAMBLE(8)
+ v3 ^= combined;
+ HSIPROUND;
+ v0 ^= combined;
+ HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_2u32);
+
+/**
+ * hsiphash_3u32 - compute 32-bit hsiphash PRF value of 3 u32
+ * @first: first u32
+ * @second: second u32
+ * @third: third u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_3u32(const u32 first, const u32 second, const u32 third,
+ const hsiphash_key_t key)
+{
+ u64 combined = (u64)second << 32 | first;
+ HPREAMBLE(12)
+ v3 ^= combined;
+ HSIPROUND;
+ v0 ^= combined;
+ b |= third;
+ HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_3u32);
+
+/**
+ * hsiphash_4u32 - compute 32-bit hsiphash PRF value of 4 u32
+ * @first: first u32
+ * @second: second u32
+ * @third: third u32
+ * @forth: forth u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_4u32(const u32 first, const u32 second, const u32 third,
+ const u32 forth, const hsiphash_key_t key)
+{
+ u64 combined = (u64)second << 32 | first;
+ HPREAMBLE(16)
+ v3 ^= combined;
+ HSIPROUND;
+ v0 ^= combined;
+ combined = (u64)forth << 32 | third;
+ v3 ^= combined;
+ HSIPROUND;
+ v0 ^= combined;
+ HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_4u32);
+#else
+#define HSIPROUND \
+ do { \
+ v0 += v1; v1 = rol32(v1, 5); v1 ^= v0; v0 = rol32(v0, 16); \
+ v2 += v3; v3 = rol32(v3, 8); v3 ^= v2; \
+ v0 += v3; v3 = rol32(v3, 7); v3 ^= v0; \
+ v2 += v1; v1 = rol32(v1, 13); v1 ^= v2; v2 = rol32(v2, 16); \
+ } while(0)
+
+#define HPREAMBLE(len) \
+ u32 v0 = 0; \
+ u32 v1 = 0; \
+ u32 v2 = 0x6c796765U; \
+ u32 v3 = 0x74656462U; \
+ u32 b = ((u32)len) << 24; \
+ v3 ^= key[1]; \
+ v2 ^= key[0]; \
+ v1 ^= key[1]; \
+ v0 ^= key[0];
+
+#define HPOSTAMBLE \
+ v3 ^= b; \
+ HSIPROUND; \
+ v0 ^= b; \
+ v2 ^= 0xff; \
+ HSIPROUND; \
+ HSIPROUND; \
+ HSIPROUND; \
+ return v1 ^ v3;
+
+u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t key)
+{
+ const u8 *end = data + len - (len % sizeof(u32));
+ const u8 left = len & (sizeof(u32) - 1);
+ u32 m;
+ HPREAMBLE(len)
+ for (; data != end; data += sizeof(u32)) {
+ m = le32_to_cpup(data);
+ v3 ^= m;
+ HSIPROUND;
+ v0 ^= m;
+ }
+ switch (left) {
+ case 3: b |= ((u32)end[2]) << 16;
+ case 2: b |= le16_to_cpup(data); break;
+ case 1: b |= end[0];
+ }
+ HPOSTAMBLE
+}
+EXPORT_SYMBOL(__hsiphash_aligned);
+
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+u32 __hsiphash_unaligned(const void *data, size_t len, const hsiphash_key_t key)
+{
+ const u8 *end = data + len - (len % sizeof(u32));
+ const u8 left = len & (sizeof(u32) - 1);
+ u32 m;
+ HPREAMBLE(len)
+ for (; data != end; data += sizeof(u32)) {
+ m = get_unaligned_le32(data);
+ v3 ^= m;
+ HSIPROUND;
+ v0 ^= m;
+ }
+ switch (left) {
+ case 3: b |= ((u32)end[2]) << 16;
+ case 2: b |= get_unaligned_le16(end); break;
+ case 1: b |= end[0];
+ }
+ HPOSTAMBLE
+}
+EXPORT_SYMBOL(__hsiphash_unaligned);
+#endif
+
+/**
+ * hsiphash_1u32 - compute 32-bit hsiphash PRF value of a u32
+ * @first: first u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_1u32(const u32 first, const hsiphash_key_t key)
+{
+ HPREAMBLE(4)
+ v3 ^= first;
+ HSIPROUND;
+ v0 ^= first;
+ HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_1u32);
+
+/**
+ * hsiphash_2u32 - compute 32-bit hsiphash PRF value of 2 u32
+ * @first: first u32
+ * @second: second u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_2u32(const u32 first, const u32 second, const hsiphash_key_t key)
+{
+ HPREAMBLE(8)
+ v3 ^= first;
+ HSIPROUND;
+ v0 ^= first;
+ v3 ^= second;
+ HSIPROUND;
+ v0 ^= second;
+ HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_2u32);
+
+/**
+ * hsiphash_3u32 - compute 32-bit hsiphash PRF value of 3 u32
+ * @first: first u32
+ * @second: second u32
+ * @third: third u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_3u32(const u32 first, const u32 second, const u32 third,
+ const hsiphash_key_t key)
+{
+ HPREAMBLE(12)
+ v3 ^= first;
+ HSIPROUND;
+ v0 ^= first;
+ v3 ^= second;
+ HSIPROUND;
+ v0 ^= second;
+ v3 ^= third;
+ HSIPROUND;
+ v0 ^= third;
+ HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_3u32);
+
+/**
+ * hsiphash_4u32 - compute 32-bit hsiphash PRF value of 4 u32
+ * @first: first u32
+ * @second: second u32
+ * @third: third u32
+ * @forth: forth u32
+ * @key: the hsiphash key
+ */
+u32 hsiphash_4u32(const u32 first, const u32 second, const u32 third,
+ const u32 forth, const hsiphash_key_t key)
+{
+ HPREAMBLE(16)
+ v3 ^= first;
+ HSIPROUND;
+ v0 ^= first;
+ v3 ^= second;
+ HSIPROUND;
+ v0 ^= second;
+ v3 ^= third;
+ HSIPROUND;
+ v0 ^= third;
+ v3 ^= forth;
+ HSIPROUND;
+ v0 ^= forth;
+ HPOSTAMBLE
+}
+EXPORT_SYMBOL(hsiphash_4u32);
+#endif
diff --git a/lib/test_siphash.c b/lib/test_siphash.c
index e0ba2cf8dc67..ac291ec27fb6 100644
--- a/lib/test_siphash.c
+++ b/lib/test_siphash.c
@@ -7,7 +7,9 @@
* SipHash: a fast short-input PRF
* https://131002.net/siphash/
*
- * This implementation is specifically for SipHash2-4.
+ * This implementation is specifically for SipHash2-4 for a secure PRF
+ * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for
+ * hashtables.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -18,10 +20,16 @@
#include <linux/errno.h>
#include <linux/module.h>
-/* Test vectors taken from official reference source available at:
- * https://131002.net/siphash/siphash24.c
+/* Test vectors taken from reference source available at:
+ * https://github.com/veorq/SipHash
*/
-static const u64 test_vectors[64] = {
+
+
+
+static const siphash_key_t test_key_siphash =
+ { 0x0706050403020100ULL , 0x0f0e0d0c0b0a0908ULL };
+
+static const u64 test_vectors_siphash[64] = {
0x726fdb47dd0e0e31ULL, 0x74f839c593dc67fdULL, 0x0d6c8009d9a94f5aULL,
0x85676696d7fb7e2dULL, 0xcf2794e0277187b7ULL, 0x18765564cd99a68dULL,
0xcbc9466e58fee3ceULL, 0xab0200f58b01d137ULL, 0x93f5f5799a932462ULL,
@@ -45,9 +53,64 @@ static const u64 test_vectors[64] = {
0x6ca4ecb15c5f91e1ULL, 0x9f626da15c9625f3ULL, 0xe51b38608ef25f57ULL,
0x958a324ceb064572ULL
};
-static const siphash_key_t test_key =
+#if BITS_PER_LONG == 64
+static const hsiphash_key_t test_key_hsiphash =
{ 0x0706050403020100ULL , 0x0f0e0d0c0b0a0908ULL };
+static const u32 test_vectors_hsiphash[64] = {
+ 0x050fc4dcU, 0x7d57ca93U, 0x4dc7d44dU,
+ 0xe7ddf7fbU, 0x88d38328U, 0x49533b67U,
+ 0xc59f22a7U, 0x9bb11140U, 0x8d299a8eU,
+ 0x6c063de4U, 0x92ff097fU, 0xf94dc352U,
+ 0x57b4d9a2U, 0x1229ffa7U, 0xc0f95d34U,
+ 0x2a519956U, 0x7d908b66U, 0x63dbd80cU,
+ 0xb473e63eU, 0x8d297d1cU, 0xa6cce040U,
+ 0x2b45f844U, 0xa320872eU, 0xdae6c123U,
+ 0x67349c8cU, 0x705b0979U, 0xca9913a5U,
+ 0x4ade3b35U, 0xef6cd00dU, 0x4ab1e1f4U,
+ 0x43c5e663U, 0x8c21d1bcU, 0x16a7b60dU,
+ 0x7a8ff9bfU, 0x1f2a753eU, 0xbf186b91U,
+ 0xada26206U, 0xa3c33057U, 0xae3a36a1U,
+ 0x7b108392U, 0x99e41531U, 0x3f1ad944U,
+ 0xc8138825U, 0xc28949a6U, 0xfaf8876bU,
+ 0x9f042196U, 0x68b1d623U, 0x8b5114fdU,
+ 0xdf074c46U, 0x12cc86b3U, 0x0a52098fU,
+ 0x9d292f9aU, 0xa2f41f12U, 0x43a71ed0U,
+ 0x73f0bce6U, 0x70a7e980U, 0x243c6d75U,
+ 0xfdb71513U, 0xa67d8a08U, 0xb7e8f148U,
+ 0xf7a644eeU, 0x0f1837f2U, 0x4b6694e0U,
+ 0xb7bbb3a8U
+};
+#else
+static const hsiphash_key_t test_key_hsiphash =
+ { 0x03020100U, 0x07060504U };
+
+static const u32 test_vectors_hsiphash[64] = {
+ 0x5814c896U, 0xe7e864caU, 0xbc4b0e30U,
+ 0x01539939U, 0x7e059ea6U, 0x88e3d89bU,
+ 0xa0080b65U, 0x9d38d9d6U, 0x577999b1U,
+ 0xc839caedU, 0xe4fa32cfU, 0x959246eeU,
+ 0x6b28096cU, 0x66dd9cd6U, 0x16658a7cU,
+ 0xd0257b04U, 0x8b31d501U, 0x2b1cd04bU,
+ 0x06712339U, 0x522aca67U, 0x911bb605U,
+ 0x90a65f0eU, 0xf826ef7bU, 0x62512debU,
+ 0x57150ad7U, 0x5d473507U, 0x1ec47442U,
+ 0xab64afd3U, 0x0a4100d0U, 0x6d2ce652U,
+ 0x2331b6a3U, 0x08d8791aU, 0xbc6dda8dU,
+ 0xe0f6c934U, 0xb0652033U, 0x9b9851ccU,
+ 0x7c46fb7fU, 0x732ba8cbU, 0xf142997aU,
+ 0xfcc9aa1bU, 0x05327eb2U, 0xe110131cU,
+ 0xf9e5e7c0U, 0xa7d708a6U, 0x11795ab1U,
+ 0x65671619U, 0x9f5fff91U, 0xd89c5267U,
+ 0x007783ebU, 0x95766243U, 0xab639262U,
+ 0x9c7e1390U, 0xc368dda6U, 0x38ddc455U,
+ 0xfa13d379U, 0x979ea4e8U, 0x53ecd77eU,
+ 0x2ee80657U, 0x33dbb66aU, 0xae3f0577U,
+ 0x88b4c4ccU, 0x3e7f480bU, 0x74c1ebf8U,
+ 0x87178304U
+};
+#endif
+
static int __init siphash_test_init(void)
{
u8 in[64] __aligned(SIPHASH_ALIGNMENT);
@@ -58,49 +121,75 @@ static int __init siphash_test_init(void)
for (i = 0; i < 64; ++i) {
in[i] = i;
in_unaligned[i + 1] = i;
- if (siphash(in, i, test_key) != test_vectors[i]) {
- pr_info("self-test aligned %u: FAIL\n", i + 1);
+ if (siphash(in, i, test_key_siphash) != test_vectors_siphash[i]) {
+ pr_info("siphash self-test aligned %u: FAIL\n", i + 1);
+ ret = -EINVAL;
+ }
+ if (siphash(in_unaligned + 1, i, test_key_siphash) != test_vectors_siphash[i]) {
+ pr_info("siphash self-test unaligned %u: FAIL\n", i + 1);
ret = -EINVAL;
}
- if (siphash(in_unaligned + 1, i, test_key) != test_vectors[i]) {
- pr_info("self-test unaligned %u: FAIL\n", i + 1);
+ if (hsiphash(in, i, test_key_hsiphash) != test_vectors_hsiphash[i]) {
+ pr_info("hsiphash self-test aligned %u: FAIL\n", i + 1);
+ ret = -EINVAL;
+ }
+ if (hsiphash(in_unaligned + 1, i, test_key_hsiphash) != test_vectors_hsiphash[i]) {
+ pr_info("hsiphash self-test unaligned %u: FAIL\n", i + 1);
ret = -EINVAL;
}
}
- if (siphash_1u64(0x0706050403020100ULL, test_key) != test_vectors[8]) {
- pr_info("self-test 1u64: FAIL\n");
+ if (siphash_1u64(0x0706050403020100ULL, test_key_siphash) != test_vectors_siphash[8]) {
+ pr_info("siphash self-test 1u64: FAIL\n");
ret = -EINVAL;
}
- if (siphash_2u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL, test_key) != test_vectors[16]) {
- pr_info("self-test 2u64: FAIL\n");
+ if (siphash_2u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL, test_key_siphash) != test_vectors_siphash[16]) {
+ pr_info("siphash self-test 2u64: FAIL\n");
ret = -EINVAL;
}
if (siphash_3u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL,
- 0x1716151413121110ULL, test_key) != test_vectors[24]) {
- pr_info("self-test 3u64: FAIL\n");
+ 0x1716151413121110ULL, test_key_siphash) != test_vectors_siphash[24]) {
+ pr_info("siphash self-test 3u64: FAIL\n");
ret = -EINVAL;
}
if (siphash_4u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL,
- 0x1716151413121110ULL, 0x1f1e1d1c1b1a1918ULL, test_key) != test_vectors[32]) {
- pr_info("self-test 4u64: FAIL\n");
+ 0x1716151413121110ULL, 0x1f1e1d1c1b1a1918ULL, test_key_siphash) != test_vectors_siphash[32]) {
+ pr_info("siphash self-test 4u64: FAIL\n");
ret = -EINVAL;
}
- if (siphash_1u32(0x03020100U, test_key) != test_vectors[4]) {
- pr_info("self-test 1u32: FAIL\n");
+ if (siphash_1u32(0x03020100U, test_key_siphash) != test_vectors_siphash[4]) {
+ pr_info("siphash self-test 1u32: FAIL\n");
ret = -EINVAL;
}
- if (siphash_2u32(0x03020100U, 0x07060504U, test_key) != test_vectors[8]) {
- pr_info("self-test 2u32: FAIL\n");
+ if (siphash_2u32(0x03020100U, 0x07060504U, test_key_siphash) != test_vectors_siphash[8]) {
+ pr_info("siphash self-test 2u32: FAIL\n");
ret = -EINVAL;
}
if (siphash_3u32(0x03020100U, 0x07060504U,
- 0x0b0a0908U, test_key) != test_vectors[12]) {
- pr_info("self-test 3u32: FAIL\n");
+ 0x0b0a0908U, test_key_siphash) != test_vectors_siphash[12]) {
+ pr_info("siphash self-test 3u32: FAIL\n");
ret = -EINVAL;
}
if (siphash_4u32(0x03020100U, 0x07060504U,
- 0x0b0a0908U, 0x0f0e0d0cU, test_key) != test_vectors[16]) {
- pr_info("self-test 4u32: FAIL\n");
+ 0x0b0a0908U, 0x0f0e0d0cU, test_key_siphash) != test_vectors_siphash[16]) {
+ pr_info("siphash self-test 4u32: FAIL\n");
+ ret = -EINVAL;
+ }
+ if (hsiphash_1u32(0x03020100U, test_key_hsiphash) != test_vectors_hsiphash[4]) {
+ pr_info("hsiphash self-test 1u32: FAIL\n");
+ ret = -EINVAL;
+ }
+ if (hsiphash_2u32(0x03020100U, 0x07060504U, test_key_hsiphash) != test_vectors_hsiphash[8]) {
+ pr_info("hsiphash self-test 2u32: FAIL\n");
+ ret = -EINVAL;
+ }
+ if (hsiphash_3u32(0x03020100U, 0x07060504U,
+ 0x0b0a0908U, test_key_hsiphash) != test_vectors_hsiphash[12]) {
+ pr_info("hsiphash self-test 3u32: FAIL\n");
+ ret = -EINVAL;
+ }
+ if (hsiphash_4u32(0x03020100U, 0x07060504U,
+ 0x0b0a0908U, 0x0f0e0d0cU, test_key_hsiphash) != test_vectors_hsiphash[16]) {
+ pr_info("hsiphash self-test 4u32: FAIL\n");
ret = -EINVAL;
}
if (!ret)
--
2.11.0
^ permalink raw reply related
* [PATCH net-next 4/4] syncookies: use SipHash in place of SHA1
From: Jason A. Donenfeld @ 2017-01-06 20:10 UTC (permalink / raw)
To: davem, netdev, linux-kernel; +Cc: Jason A. Donenfeld, Eric Dumazet
In-Reply-To: <20170106201055.13765-1-Jason@zx2c4.com>
SHA1 is slower and less secure than SipHash, and so replacing syncookie
generation with SipHash makes natural sense. Some BSDs have been doing
this for several years in fact.
The speedup should be similar -- and even more impressive -- to the
speedup from the sequence number fix in this series.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: David Miller <davem@davemloft.net>
---
net/ipv4/syncookies.c | 20 ++++----------------
net/ipv6/syncookies.c | 37 ++++++++++++++++---------------------
2 files changed, 20 insertions(+), 37 deletions(-)
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 3e88467d70ee..03bb068f8888 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -13,13 +13,13 @@
#include <linux/tcp.h>
#include <linux/slab.h>
#include <linux/random.h>
-#include <linux/cryptohash.h>
+#include <linux/siphash.h>
#include <linux/kernel.h>
#include <linux/export.h>
#include <net/tcp.h>
#include <net/route.h>
-static u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS] __read_mostly;
+static siphash_key_t syncookie_secret[2] __read_mostly;
#define COOKIEBITS 24 /* Upper bits store count */
#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
@@ -48,24 +48,12 @@ static u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS] __read_mostly;
#define TSBITS 6
#define TSMASK (((__u32)1 << TSBITS) - 1)
-static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS], ipv4_cookie_scratch);
-
static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport,
u32 count, int c)
{
- __u32 *tmp;
-
net_get_random_once(syncookie_secret, sizeof(syncookie_secret));
-
- tmp = this_cpu_ptr(ipv4_cookie_scratch);
- memcpy(tmp + 4, syncookie_secret[c], sizeof(syncookie_secret[c]));
- tmp[0] = (__force u32)saddr;
- tmp[1] = (__force u32)daddr;
- tmp[2] = ((__force u32)sport << 16) + (__force u32)dport;
- tmp[3] = count;
- sha_transform(tmp + 16, (__u8 *)tmp, tmp + 16 + 5);
-
- return tmp[17];
+ return siphash_4u32(saddr, daddr, (u32)sport << 16 | dport, count,
+ syncookie_secret[c]);
}
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index a4d49760bf43..be51fc0d99ad 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -16,7 +16,7 @@
#include <linux/tcp.h>
#include <linux/random.h>
-#include <linux/cryptohash.h>
+#include <linux/siphash.h>
#include <linux/kernel.h>
#include <net/ipv6.h>
#include <net/tcp.h>
@@ -24,7 +24,7 @@
#define COOKIEBITS 24 /* Upper bits store count */
#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
-static u32 syncookie6_secret[2][16-4+SHA_DIGEST_WORDS] __read_mostly;
+static siphash_key_t syncookie6_secret[2] __read_mostly;
/* RFC 2460, Section 8.3:
* [ipv6 tcp] MSS must be computed as the maximum packet size minus 60 [..]
@@ -41,30 +41,25 @@ static __u16 const msstab[] = {
9000 - 60,
};
-static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS], ipv6_cookie_scratch);
-
static u32 cookie_hash(const struct in6_addr *saddr, const struct in6_addr *daddr,
__be16 sport, __be16 dport, u32 count, int c)
{
- __u32 *tmp;
+ const struct {
+ struct in6_addr saddr;
+ struct in6_addr daddr;
+ u32 count;
+ u16 sport;
+ u16 dport;
+ } __aligned(SIPHASH_ALIGNMENT) combined = {
+ .saddr = *saddr,
+ .daddr = *daddr,
+ .count = count,
+ .sport = sport,
+ .dport = dport
+ };
net_get_random_once(syncookie6_secret, sizeof(syncookie6_secret));
-
- tmp = this_cpu_ptr(ipv6_cookie_scratch);
-
- /*
- * we have 320 bits of information to hash, copy in the remaining
- * 192 bits required for sha_transform, from the syncookie6_secret
- * and overwrite the digest with the secret
- */
- memcpy(tmp + 10, syncookie6_secret[c], 44);
- memcpy(tmp, saddr, 16);
- memcpy(tmp + 4, daddr, 16);
- tmp[8] = ((__force u32)sport << 16) + (__force u32)dport;
- tmp[9] = count;
- sha_transform(tmp + 16, (__u8 *)tmp, tmp + 16 + 5);
-
- return tmp[17];
+ return siphash(&combined, offsetofend(typeof(combined), dport), syncookie6_secret[c]);
}
static __u32 secure_tcp_syn_cookie(const struct in6_addr *saddr,
--
2.11.0
^ permalink raw reply related
* Re: [PATCH net] net: Fix inconsistent rtnl_lock usage on dev_get_stats().
From: Eric Dumazet @ 2017-01-06 20:13 UTC (permalink / raw)
To: David Miller; +Cc: michael.chan, netdev
In-Reply-To: <20170106.130134.50153126758574257.davem@davemloft.net>
On Fri, 2017-01-06 at 13:01 -0500, David Miller wrote:
> From: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Fri, 06 Jan 2017 09:32:56 -0800
>
> > This makes no sense to me.
> >
> > RTNL is absolutely not needed to get device stats.
> >
> > We try to not add RTNL, especially when not required.
> >
> > Sure, RTNETLINK dumps currently hold RTNL, but we had various attempts
> > in the past to get rid of this behavior.
> >
> > If a device driver expects RTNL being locked, it is clearly a bug that
> > needs a fix anyway.
>
> This is extremely problematic when the driver has to synchronize some
> piece of state between the get stats method and open/close. It is
> exactly the case we are trying to solve in tg3, and lots of drivers
> end up hitting the same exact issue.
>
> If open/close can happen asynchronously to get stats, it is very hard
> to make dynamically allocated data structures or DMA buffers usable
> from the stats call.
Yes, I had some issues lately with mlx4. netdevices are protected by
RCU, adding proper RCU logic for the stats is doable.
>
> Drivers in this situation will just add a mutex specifically for this
> situation if we don't consistently apply RTNL locking here.
Well, there are cases where RTNL is quite contended, but supervisions
like to get /proc/net/devices or various sysfs attributes
(netstat_show() can be called very very often
for /sys/class/net/*/statistics/*) in a reasonable amount of time.
I fear that such a change will add drifts, when devices are constantly
added/removed.
^ permalink raw reply
* Re: [PATCH net-next] liquidio VF: fix incorrect struct being used
From: David Miller @ 2017-01-06 20:31 UTC (permalink / raw)
To: felix.manlunas; +Cc: netdev, raghu.vatsavayi, derek.chickles, satananda.burla
In-Reply-To: <20170104193155.GA19084@felix.cavium.com>
From: Felix Manlunas <felix.manlunas@cavium.com>
Date: Wed, 4 Jan 2017 11:31:55 -0800
> From: Prasad Kanneganti <prasad.kanneganti@cavium.com>
>
> The VF driver is using the wrong struct when sending commands to the NIC
> firmware, sometimes causing adverse effects in the firmware. The right
> struct is the one that the PF is using, so make the VF use that as well.
>
> Signed-off-by: Prasad Kanneganti <prasad.kanneganti@cavium.com>
> Signed-off-by: Felix Manlunas <felix.manlunas@cavium.com>
> Signed-off-by: Derek Chickles <derek.chickles@cavium.com>
> Signed-off-by: Satanand Burla <satananda.burla@cavium.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next 1/4] siphash: add cryptographically secure PRF
From: Jean-Philippe Aumasson @ 2017-01-06 20:32 UTC (permalink / raw)
To: Jason A. Donenfeld
Cc: David Miller, Netdev, LKML, Linus Torvalds, Eric Biggers,
David Laight, Eric Dumazet
In-Reply-To: <20170106201055.13765-2-Jason@zx2c4.com>
>
>
> On Fri, Jan 6, 2017 at 9:11 PM Jason A. Donenfeld <Jason@zx2c4.com> wrote:
>
> SipHash is a 64-bit keyed hash function that is actually a
> cryptographically secure PRF, like HMAC. Except SipHash is super fast,
> and is meant to be used as a hashtable keyed lookup function, or as a
> general PRF for short input use cases, such as sequence numbers or RNG
> chaining.
>
> For the first usage:
>
> There are a variety of attacks known as "hashtable poisoning" in which an
> attacker forms some data such that the hash of that data will be the
> same, and then preceeds to fill up all entries of a hashbucket. This is
> a realistic and well-known denial-of-service vector. Currently
> hashtables use jhash, which is fast but not secure, and some kind of
> rotating key scheme (or none at all, which isn't good). SipHash is meant
> as a replacement for jhash in these cases.
>
> There are a modicum of places in the kernel that are vulnerable to
> hashtable poisoning attacks, either via userspace vectors or network
> vectors, and there's not a reliable mechanism inside the kernel at the
> moment to fix it. The first step toward fixing these issues is actually
> getting a secure primitive into the kernel for developers to use. Then
> we can, bit by bit, port things over to it as deemed appropriate.
>
> While SipHash is extremely fast for a cryptographically secure function,
> it is likely a bit slower than the insecure jhash, and so replacements
> will be evaluated on a case-by-case basis based on whether or not the
> difference in speed is negligible and whether or not the current jhash usage
> poses a real security risk.
>
> For the second usage:
>
> A few places in the kernel are using MD5 or SHA1 for creating secure
> sequence numbers, syn cookies, port numbers, or fast random numbers.
> SipHash is a faster and more fitting, and more secure replacement for MD5
> in those situations. Replacing MD5 and SHA1 with SipHash for these uses is
> obvious and straight-forward, and so is submitted along with this patch
> series. There shouldn't be much of a debate over its efficacy.
>
> Dozens of languages are already using this internally for their hash
> tables and PRFs. Some of the BSDs already use this in their kernels.
> SipHash is a widely known high-speed solution to a widely known set of
> problems, and it's time we catch-up.
>
> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
> Cc: Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
> Cc: Linus Torvalds <torvalds@linux-foundation.org>
> Cc: Eric Biggers <ebiggers3@gmail.com>
> Cc: David Laight <David.Laight@aculab.com>
> Cc: Eric Dumazet <eric.dumazet@gmail.com>
> ---
> Documentation/siphash.txt | 79 ++++++++++++++++
> MAINTAINERS | 7 ++
> include/linux/siphash.h | 79 ++++++++++++++++
> lib/Kconfig.debug | 6 +-
> lib/Makefile | 5 +-
> lib/siphash.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++
> lib/test_siphash.c | 119 ++++++++++++++++++++++++
> 7 files changed, 522 insertions(+), 5 deletions(-)
> create mode 100644 Documentation/siphash.txt
> create mode 100644 include/linux/siphash.h
> create mode 100644 lib/siphash.c
> create mode 100644 lib/test_siphash.c
>
> diff --git a/Documentation/siphash.txt b/Documentation/siphash.txt
> new file mode 100644
> index 000000000000..39ff7f0438e7
> --- /dev/null
> +++ b/Documentation/siphash.txt
> @@ -0,0 +1,79 @@
> + SipHash - a short input PRF
> +-----------------------------------------------
> +Written by Jason A. Donenfeld <jason@zx2c4.com>
> +
> +SipHash is a cryptographically secure PRF -- a keyed hash function -- that
> +performs very well for short inputs, hence the name. It was designed by
> +cryptographers Daniel J. Bernstein and Jean-Philippe Aumasson. It is intended
> +as a replacement for some uses of: `jhash`, `md5_transform`, `sha_transform`,
> +and so forth.
> +
> +SipHash takes a secret key filled with randomly generated numbers and either
> +an input buffer or several input integers. It spits out an integer that is
> +indistinguishable from random. You may then use that integer as part of secure
> +sequence numbers, secure cookies, or mask it off for use in a hash table.
> +
> +1. Generating a key
> +
> +Keys should always be generated from a cryptographically secure source of
> +random numbers, either using get_random_bytes or get_random_once:
> +
> +siphash_key_t key;
> +get_random_bytes(key, sizeof(key));
> +
> +If you're not deriving your key from here, you're doing it wrong.
> +
> +2. Using the functions
> +
> +There are two variants of the function, one that takes a list of integers, and
> +one that takes a buffer:
> +
> +u64 siphash(const void *data, size_t len, siphash_key_t key);
> +
> +And:
> +
> +u64 siphash_1u64(u64, siphash_key_t key);
> +u64 siphash_2u64(u64, u64, siphash_key_t key);
> +u64 siphash_3u64(u64, u64, u64, siphash_key_t key);
> +u64 siphash_4u64(u64, u64, u64, u64, siphash_key_t key);
> +u64 siphash_1u32(u32, siphash_key_t key);
> +u64 siphash_2u32(u32, u32, siphash_key_t key);
> +u64 siphash_3u32(u32, u32, u32, siphash_key_t key);
> +u64 siphash_4u32(u32, u32, u32, u32, siphash_key_t key);
> +
> +If you pass the generic siphash function something of a constant length, it
> +will constant fold at compile-time and automatically choose one of the
> +optimized functions.
> +
> +3. Hashtable key function usage:
> +
> +struct some_hashtable {
> + DECLARE_HASHTABLE(hashtable, 8);
> + siphash_key_t key;
> +};
> +
> +void init_hashtable(struct some_hashtable *table)
> +{
> + get_random_bytes(table->key, sizeof(table->key));
> +}
> +
> +static inline hlist_head *some_hashtable_bucket(struct some_hashtable *table, struct interesting_input *input)
> +{
> + return &table->hashtable[siphash(input, sizeof(*input), table->key) & (HASH_SIZE(table->hashtable) - 1)];
> +}
> +
> +You may then iterate like usual over the returned hash bucket.
> +
> +4. Security
> +
> +SipHash has a very high security margin, with its 128-bit key. So long as the
> +key is kept secret, it is impossible for an attacker to guess the outputs of
> +the function, even if being able to observe many outputs, since 2^128 outputs
> +is significant.
> +
> +Linux implements the "2-4" variant of SipHash.
> +
> +5. Resources
> +
> +Read the SipHash paper if you're interested in learning more:
> +https://131002.net/siphash/siphash.pdf
> diff --git a/MAINTAINERS b/MAINTAINERS
> index cfff2c9e3d94..e1384ae37344 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11291,6 +11291,13 @@ F: arch/arm/mach-s3c24xx/mach-bast.c
> F: arch/arm/mach-s3c24xx/bast-ide.c
> F: arch/arm/mach-s3c24xx/bast-irq.c
>
> +SIPHASH PRF ROUTINES
> +M: Jason A. Donenfeld <Jason@zx2c4.com>
> +S: Maintained
> +F: lib/siphash.c
> +F: lib/test_siphash.c
> +F: include/linux/siphash.h
> +
> TI DAVINCI MACHINE SUPPORT
> M: Sekhar Nori <nsekhar@ti.com>
> M: Kevin Hilman <khilman@kernel.org>
> diff --git a/include/linux/siphash.h b/include/linux/siphash.h
> new file mode 100644
> index 000000000000..7aa666eb00d9
> --- /dev/null
> +++ b/include/linux/siphash.h
> @@ -0,0 +1,79 @@
> +/* Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
> + *
> + * This file is provided under a dual BSD/GPLv2 license.
> + *
> + * SipHash: a fast short-input PRF
> + * https://131002.net/siphash/
> + *
> + * This implementation is specifically for SipHash2-4.
> + */
> +
> +#ifndef _LINUX_SIPHASH_H
> +#define _LINUX_SIPHASH_H
> +
> +#include <linux/types.h>
> +#include <linux/kernel.h>
> +
> +#define SIPHASH_ALIGNMENT __alignof__(u64)
> +typedef u64 siphash_key_t[2];
> +
> +u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t key);
> +#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
> +u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t key);
> +#endif
> +
> +u64 siphash_1u64(const u64 a, const siphash_key_t key);
> +u64 siphash_2u64(const u64 a, const u64 b, const siphash_key_t key);
> +u64 siphash_3u64(const u64 a, const u64 b, const u64 c,
> + const siphash_key_t key);
> +u64 siphash_4u64(const u64 a, const u64 b, const u64 c, const u64 d,
> + const siphash_key_t key);
> +u64 siphash_1u32(const u32 a, const siphash_key_t key);
> +u64 siphash_3u32(const u32 a, const u32 b, const u32 c, const siphash_key_t key);
> +
> +static inline u64 siphash_2u32(const u32 a, const u32 b, const siphash_key_t key)
> +{
> + return siphash_1u64((u64)b << 32 | a, key);
> +}
> +static inline u64 siphash_4u32(const u32 a, const u32 b, const u32 c, const u32 d,
> + const siphash_key_t key)
> +{
> + return siphash_2u64((u64)b << 32 | a, (u64)d << 32 | c, key);
> +}
> +
> +
> +static inline u64 ___siphash_aligned(const __le64 *data, size_t len, const siphash_key_t key)
> +{
> + if (__builtin_constant_p(len) && len == 4)
> + return siphash_1u32(le32_to_cpu(data[0]), key);
> + if (__builtin_constant_p(len) && len == 8)
> + return siphash_1u64(le64_to_cpu(data[0]), key);
> + if (__builtin_constant_p(len) && len == 16)
> + return siphash_2u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]),
> + key);
> + if (__builtin_constant_p(len) && len == 24)
> + return siphash_3u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]),
> + le64_to_cpu(data[2]), key);
> + if (__builtin_constant_p(len) && len == 32)
> + return siphash_4u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]),
> + le64_to_cpu(data[2]), le64_to_cpu(data[3]),
> + key);
> + return __siphash_aligned(data, len, key);
> +}
> +
> +/**
> + * siphash - compute 64-bit siphash PRF value
> + * @data: buffer to hash
> + * @size: size of @data
> + * @key: the siphash key
> + */
> +static inline u64 siphash(const void *data, size_t len, const siphash_key_t key)
> +{
> +#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
> + if (!IS_ALIGNED((unsigned long)data, SIPHASH_ALIGNMENT))
> + return __siphash_unaligned(data, len, key);
> +#endif
> + return ___siphash_aligned(data, len, key);
> +}
> +
> +#endif /* _LINUX_SIPHASH_H */
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index b06848a104e6..3d2515a770c3 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -1819,9 +1819,9 @@ config TEST_HASH
> tristate "Perform selftest on hash functions"
> default n
> help
> - Enable this option to test the kernel's integer (<linux/hash,h>)
> - and string (<linux/stringhash.h>) hash functions on boot
> - (or module load).
> + Enable this option to test the kernel's integer (<linux/hash.h>),
> + string (<linux/stringhash.h>), and siphash (<linux/siphash.h>)
> + hash functions on boot (or module load).
>
> This is intended to help people writing architecture-specific
> optimized versions. If unsure, say N.
> diff --git a/lib/Makefile b/lib/Makefile
> index bc4073a8cd08..7b3008d58600 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -22,7 +22,8 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
> sha1.o chacha20.o md5.o irq_regs.o argv_split.o \
> flex_proportions.o ratelimit.o show_mem.o \
> is_single_threaded.o plist.o decompress.o kobject_uevent.o \
> - earlycpio.o seq_buf.o nmi_backtrace.o nodemask.o win_minmax.o
> + earlycpio.o seq_buf.o siphash.o \
> + nmi_backtrace.o nodemask.o win_minmax.o
>
> lib-$(CONFIG_MMU) += ioremap.o
> lib-$(CONFIG_SMP) += cpumask.o
> @@ -44,7 +45,7 @@ obj-$(CONFIG_TEST_HEXDUMP) += test_hexdump.o
> obj-y += kstrtox.o
> obj-$(CONFIG_TEST_BPF) += test_bpf.o
> obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o
> -obj-$(CONFIG_TEST_HASH) += test_hash.o
> +obj-$(CONFIG_TEST_HASH) += test_hash.o test_siphash.o
> obj-$(CONFIG_TEST_KASAN) += test_kasan.o
> obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
> obj-$(CONFIG_TEST_LKM) += test_module.o
> diff --git a/lib/siphash.c b/lib/siphash.c
> new file mode 100644
> index 000000000000..ff2151313667
> --- /dev/null
> +++ b/lib/siphash.c
> @@ -0,0 +1,232 @@
> +/* Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
> + *
> + * This file is provided under a dual BSD/GPLv2 license.
> + *
> + * SipHash: a fast short-input PRF
> + * https://131002.net/siphash/
> + *
> + * This implementation is specifically for SipHash2-4.
> + */
> +
> +#include <linux/siphash.h>
> +#include <asm/unaligned.h>
> +
> +#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
> +#include <linux/dcache.h>
> +#include <asm/word-at-a-time.h>
> +#endif
> +
> +#define SIPROUND \
> + do { \
> + v0 += v1; v1 = rol64(v1, 13); v1 ^= v0; v0 = rol64(v0, 32); \
> + v2 += v3; v3 = rol64(v3, 16); v3 ^= v2; \
> + v0 += v3; v3 = rol64(v3, 21); v3 ^= v0; \
> + v2 += v1; v1 = rol64(v1, 17); v1 ^= v2; v2 = rol64(v2, 32); \
> + } while(0)
> +
> +#define PREAMBLE(len) \
> + u64 v0 = 0x736f6d6570736575ULL; \
> + u64 v1 = 0x646f72616e646f6dULL; \
> + u64 v2 = 0x6c7967656e657261ULL; \
> + u64 v3 = 0x7465646279746573ULL; \
> + u64 b = ((u64)len) << 56; \
> + v3 ^= key[1]; \
> + v2 ^= key[0]; \
> + v1 ^= key[1]; \
> + v0 ^= key[0];
> +
> +#define POSTAMBLE \
> + v3 ^= b; \
> + SIPROUND; \
> + SIPROUND; \
> + v0 ^= b; \
> + v2 ^= 0xff; \
> + SIPROUND; \
> + SIPROUND; \
> + SIPROUND; \
> + SIPROUND; \
> + return (v0 ^ v1) ^ (v2 ^ v3);
> +
> +u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t key)
> +{
> + const u8 *end = data + len - (len % sizeof(u64));
> + const u8 left = len & (sizeof(u64) - 1);
> + u64 m;
> + PREAMBLE(len)
> + for (; data != end; data += sizeof(u64)) {
> + m = le64_to_cpup(data);
> + v3 ^= m;
> + SIPROUND;
> + SIPROUND;
> + v0 ^= m;
> + }
> +#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
> + if (left)
> + b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
> + bytemask_from_count(left)));
> +#else
> + switch (left) {
> + case 7: b |= ((u64)end[6]) << 48;
> + case 6: b |= ((u64)end[5]) << 40;
> + case 5: b |= ((u64)end[4]) << 32;
> + case 4: b |= le32_to_cpup(data); break;
> + case 3: b |= ((u64)end[2]) << 16;
> + case 2: b |= le16_to_cpup(data); break;
> + case 1: b |= end[0];
> + }
> +#endif
> + POSTAMBLE
> +}
> +EXPORT_SYMBOL(__siphash_aligned);
> +
> +#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
> +u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t key)
> +{
> + const u8 *end = data + len - (len % sizeof(u64));
> + const u8 left = len & (sizeof(u64) - 1);
> + u64 m;
> + PREAMBLE(len)
> + for (; data != end; data += sizeof(u64)) {
> + m = get_unaligned_le64(data);
> + v3 ^= m;
> + SIPROUND;
> + SIPROUND;
> + v0 ^= m;
> + }
> +#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
> + if (left)
> + b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
> + bytemask_from_count(left)));
> +#else
> + switch (left) {
> + case 7: b |= ((u64)end[6]) << 48;
> + case 6: b |= ((u64)end[5]) << 40;
> + case 5: b |= ((u64)end[4]) << 32;
> + case 4: b |= get_unaligned_le32(end); break;
> + case 3: b |= ((u64)end[2]) << 16;
> + case 2: b |= get_unaligned_le16(end); break;
> + case 1: b |= end[0];
> + }
> +#endif
> + POSTAMBLE
> +}
> +EXPORT_SYMBOL(__siphash_unaligned);
> +#endif
> +
> +/**
> + * siphash_1u64 - compute 64-bit siphash PRF value of a u64
> + * @first: first u64
> + * @key: the siphash key
> + */
> +u64 siphash_1u64(const u64 first, const siphash_key_t key)
> +{
> + PREAMBLE(8)
> + v3 ^= first;
> + SIPROUND;
> + SIPROUND;
> + v0 ^= first;
> + POSTAMBLE
> +}
> +EXPORT_SYMBOL(siphash_1u64);
> +
> +/**
> + * siphash_2u64 - compute 64-bit siphash PRF value of 2 u64
> + * @first: first u64
> + * @second: second u64
> + * @key: the siphash key
> + */
> +u64 siphash_2u64(const u64 first, const u64 second, const siphash_key_t key)
> +{
> + PREAMBLE(16)
> + v3 ^= first;
> + SIPROUND;
> + SIPROUND;
> + v0 ^= first;
> + v3 ^= second;
> + SIPROUND;
> + SIPROUND;
> + v0 ^= second;
> + POSTAMBLE
> +}
> +EXPORT_SYMBOL(siphash_2u64);
> +
> +/**
> + * siphash_3u64 - compute 64-bit siphash PRF value of 3 u64
> + * @first: first u64
> + * @second: second u64
> + * @third: third u64
> + * @key: the siphash key
> + */
> +u64 siphash_3u64(const u64 first, const u64 second, const u64 third,
> + const siphash_key_t key)
> +{
> + PREAMBLE(24)
> + v3 ^= first;
> + SIPROUND;
> + SIPROUND;
> + v0 ^= first;
> + v3 ^= second;
> + SIPROUND;
> + SIPROUND;
> + v0 ^= second;
> + v3 ^= third;
> + SIPROUND;
> + SIPROUND;
> + v0 ^= third;
> + POSTAMBLE
> +}
> +EXPORT_SYMBOL(siphash_3u64);
> +
> +/**
> + * siphash_4u64 - compute 64-bit siphash PRF value of 4 u64
> + * @first: first u64
> + * @second: second u64
> + * @third: third u64
> + * @forth: forth u64
> + * @key: the siphash key
> + */
> +u64 siphash_4u64(const u64 first, const u64 second, const u64 third,
> + const u64 forth, const siphash_key_t key)
> +{
> + PREAMBLE(32)
> + v3 ^= first;
> + SIPROUND;
> + SIPROUND;
> + v0 ^= first;
> + v3 ^= second;
> + SIPROUND;
> + SIPROUND;
> + v0 ^= second;
> + v3 ^= third;
> + SIPROUND;
> + SIPROUND;
> + v0 ^= third;
> + v3 ^= forth;
> + SIPROUND;
> + SIPROUND;
> + v0 ^= forth;
> + POSTAMBLE
> +}
> +EXPORT_SYMBOL(siphash_4u64);
> +
> +u64 siphash_1u32(const u32 first, const siphash_key_t key)
> +{
> + PREAMBLE(4)
> + b |= first;
> + POSTAMBLE
> +}
> +EXPORT_SYMBOL(siphash_1u32);
> +
> +u64 siphash_3u32(const u32 first, const u32 second, const u32 third,
> + const siphash_key_t key)
> +{
> + u64 combined = (u64)second << 32 | first;
> + PREAMBLE(12)
> + v3 ^= combined;
> + SIPROUND;
> + SIPROUND;
> + v0 ^= combined;
> + b |= third;
> + POSTAMBLE
> +}
> +EXPORT_SYMBOL(siphash_3u32);
> diff --git a/lib/test_siphash.c b/lib/test_siphash.c
> new file mode 100644
> index 000000000000..e0ba2cf8dc67
> --- /dev/null
> +++ b/lib/test_siphash.c
> @@ -0,0 +1,119 @@
> +/* Test cases for siphash.c
> + *
> + * Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
> + *
> + * This file is provided under a dual BSD/GPLv2 license.
> + *
> + * SipHash: a fast short-input PRF
> + * https://131002.net/siphash/
> + *
> + * This implementation is specifically for SipHash2-4.
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/siphash.h>
> +#include <linux/kernel.h>
> +#include <linux/string.h>
> +#include <linux/errno.h>
> +#include <linux/module.h>
> +
> +/* Test vectors taken from official reference source available at:
> + * https://131002.net/siphash/siphash24.c
> + */
> +static const u64 test_vectors[64] = {
> + 0x726fdb47dd0e0e31ULL, 0x74f839c593dc67fdULL, 0x0d6c8009d9a94f5aULL,
> + 0x85676696d7fb7e2dULL, 0xcf2794e0277187b7ULL, 0x18765564cd99a68dULL,
> + 0xcbc9466e58fee3ceULL, 0xab0200f58b01d137ULL, 0x93f5f5799a932462ULL,
> + 0x9e0082df0ba9e4b0ULL, 0x7a5dbbc594ddb9f3ULL, 0xf4b32f46226bada7ULL,
> + 0x751e8fbc860ee5fbULL, 0x14ea5627c0843d90ULL, 0xf723ca908e7af2eeULL,
> + 0xa129ca6149be45e5ULL, 0x3f2acc7f57c29bdbULL, 0x699ae9f52cbe4794ULL,
> + 0x4bc1b3f0968dd39cULL, 0xbb6dc91da77961bdULL, 0xbed65cf21aa2ee98ULL,
> + 0xd0f2cbb02e3b67c7ULL, 0x93536795e3a33e88ULL, 0xa80c038ccd5ccec8ULL,
> + 0xb8ad50c6f649af94ULL, 0xbce192de8a85b8eaULL, 0x17d835b85bbb15f3ULL,
> + 0x2f2e6163076bcfadULL, 0xde4daaaca71dc9a5ULL, 0xa6a2506687956571ULL,
> + 0xad87a3535c49ef28ULL, 0x32d892fad841c342ULL, 0x7127512f72f27cceULL,
> + 0xa7f32346f95978e3ULL, 0x12e0b01abb051238ULL, 0x15e034d40fa197aeULL,
> + 0x314dffbe0815a3b4ULL, 0x027990f029623981ULL, 0xcadcd4e59ef40c4dULL,
> + 0x9abfd8766a33735cULL, 0x0e3ea96b5304a7d0ULL, 0xad0c42d6fc585992ULL,
> + 0x187306c89bc215a9ULL, 0xd4a60abcf3792b95ULL, 0xf935451de4f21df2ULL,
> + 0xa9538f0419755787ULL, 0xdb9acddff56ca510ULL, 0xd06c98cd5c0975ebULL,
> + 0xe612a3cb9ecba951ULL, 0xc766e62cfcadaf96ULL, 0xee64435a9752fe72ULL,
> + 0xa192d576b245165aULL, 0x0a8787bf8ecb74b2ULL, 0x81b3e73d20b49b6fULL,
> + 0x7fa8220ba3b2eceaULL, 0x245731c13ca42499ULL, 0xb78dbfaf3a8d83bdULL,
> + 0xea1ad565322a1a0bULL, 0x60e61c23a3795013ULL, 0x6606d7e446282b93ULL,
> + 0x6ca4ecb15c5f91e1ULL, 0x9f626da15c9625f3ULL, 0xe51b38608ef25f57ULL,
> + 0x958a324ceb064572ULL
> +};
> +static const siphash_key_t test_key =
> + { 0x0706050403020100ULL , 0x0f0e0d0c0b0a0908ULL };
> +
> +static int __init siphash_test_init(void)
> +{
> + u8 in[64] __aligned(SIPHASH_ALIGNMENT);
> + u8 in_unaligned[65];
> + u8 i;
> + int ret = 0;
> +
> + for (i = 0; i < 64; ++i) {
> + in[i] = i;
> + in_unaligned[i + 1] = i;
> + if (siphash(in, i, test_key) != test_vectors[i]) {
> + pr_info("self-test aligned %u: FAIL\n", i + 1);
> + ret = -EINVAL;
> + }
> + if (siphash(in_unaligned + 1, i, test_key) != test_vectors[i]) {
> + pr_info("self-test unaligned %u: FAIL\n", i + 1);
> + ret = -EINVAL;
> + }
> + }
> + if (siphash_1u64(0x0706050403020100ULL, test_key) != test_vectors[8]) {
> + pr_info("self-test 1u64: FAIL\n");
> + ret = -EINVAL;
> + }
> + if (siphash_2u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL, test_key) != test_vectors[16]) {
> + pr_info("self-test 2u64: FAIL\n");
> + ret = -EINVAL;
> + }
> + if (siphash_3u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL,
> + 0x1716151413121110ULL, test_key) != test_vectors[24]) {
> + pr_info("self-test 3u64: FAIL\n");
> + ret = -EINVAL;
> + }
> + if (siphash_4u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL,
> + 0x1716151413121110ULL, 0x1f1e1d1c1b1a1918ULL, test_key) != test_vectors[32]) {
> + pr_info("self-test 4u64: FAIL\n");
> + ret = -EINVAL;
> + }
> + if (siphash_1u32(0x03020100U, test_key) != test_vectors[4]) {
> + pr_info("self-test 1u32: FAIL\n");
> + ret = -EINVAL;
> + }
> + if (siphash_2u32(0x03020100U, 0x07060504U, test_key) != test_vectors[8]) {
> + pr_info("self-test 2u32: FAIL\n");
> + ret = -EINVAL;
> + }
> + if (siphash_3u32(0x03020100U, 0x07060504U,
> + 0x0b0a0908U, test_key) != test_vectors[12]) {
> + pr_info("self-test 3u32: FAIL\n");
> + ret = -EINVAL;
> + }
> + if (siphash_4u32(0x03020100U, 0x07060504U,
> + 0x0b0a0908U, 0x0f0e0d0cU, test_key) != test_vectors[16]) {
> + pr_info("self-test 4u32: FAIL\n");
> + ret = -EINVAL;
> + }
> + if (!ret)
> + pr_info("self-tests: pass\n");
> + return ret;
> +}
> +
> +static void __exit siphash_test_exit(void)
> +{
> +}
> +
> +module_init(siphash_test_init);
> +module_exit(siphash_test_exit);
> +
> +MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");
> +MODULE_LICENSE("Dual BSD/GPL");
> --
> 2.11.0
Looks good to me (co-designer of SipHash).
Reviewed-by: Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
^ permalink raw reply
* Re: [PATCH net-next 2/4] siphash: implement HalfSipHash1-3 for hash tables
From: Jean-Philippe Aumasson @ 2017-01-06 20:33 UTC (permalink / raw)
To: Jason A. Donenfeld; +Cc: David Miller, Netdev, LKML
In-Reply-To: <20170106201055.13765-3-Jason@zx2c4.com>
On Fri, Jan 6, 2017 at 9:10 PM, Jason A. Donenfeld <Jason@zx2c4.com> wrote:
> HalfSipHash, or hsiphash, is a shortened version of SipHash, which
> generates 32-bit outputs using a weaker 64-bit key. It has *much* lower
> security margins, and shouldn't be used for anything too sensitive, but
> it could be used as a hashtable key function replacement, if the output
> is never exposed, and if the security requirement is not too high.
>
> The goal is to make this something that performance-critical jhash users
> would be willing to use.
>
> On 64-bit machines, HalfSipHash1-3 is slower than SipHash1-3, so we alias
> SipHash1-3 to HalfSipHash1-3 on those systems.
>
> 64-bit x86_64:
> [ 0.509409] test_siphash: SipHash2-4 cycles: 4049181
> [ 0.510650] test_siphash: SipHash1-3 cycles: 2512884
> [ 0.512205] test_siphash: HalfSipHash1-3 cycles: 3429920
> [ 0.512904] test_siphash: JenkinsHash cycles: 978267
> So, we map hsiphash() -> SipHash1-3
>
> 32-bit x86:
> [ 0.509868] test_siphash: SipHash2-4 cycles: 14812892
> [ 0.513601] test_siphash: SipHash1-3 cycles: 9510710
> [ 0.515263] test_siphash: HalfSipHash1-3 cycles: 3856157
> [ 0.515952] test_siphash: JenkinsHash cycles: 1148567
> So, we map hsiphash() -> HalfSipHash1-3
>
> hsiphash() is roughly 3 times slower than jhash(), but comes with a
> considerable security improvement.
>
> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
> Cc: Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
> ---
> Documentation/siphash.txt | 75 +++++++++++
> include/linux/siphash.h | 56 +++++++-
> lib/siphash.c | 318 +++++++++++++++++++++++++++++++++++++++++++++-
> lib/test_siphash.c | 139 ++++++++++++++++----
> 4 files changed, 561 insertions(+), 27 deletions(-)
>
> diff --git a/Documentation/siphash.txt b/Documentation/siphash.txt
> index 39ff7f0438e7..f93c1d7104c4 100644
> --- a/Documentation/siphash.txt
> +++ b/Documentation/siphash.txt
> @@ -77,3 +77,78 @@ Linux implements the "2-4" variant of SipHash.
>
> Read the SipHash paper if you're interested in learning more:
> https://131002.net/siphash/siphash.pdf
> +
> +
> +~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
> +
> +HalfSipHash - SipHash's insecure younger cousin
> +-----------------------------------------------
> +Written by Jason A. Donenfeld <jason@zx2c4.com>
> +
> +On the off-chance that SipHash is not fast enough for your needs, you might be
> +able to justify using HalfSipHash, a terrifying but potentially useful
> +possibility. HalfSipHash cuts SipHash's rounds down from "2-4" to "1-3" and,
> +even scarier, uses an easily brute-forcable 64-bit key (with a 32-bit output)
> +instead of SipHash's 128-bit key. However, this may appeal to some
> +high-performance `jhash` users.
> +
> +Danger!
> +
> +Do not ever use HalfSipHash except for as a hashtable key function, and only
> +then when you can be absolutely certain that the outputs will never be
> +transmitted out of the kernel. This is only remotely useful over `jhash` as a
> +means of mitigating hashtable flooding denial of service attacks.
> +
> +1. Generating a key
> +
> +Keys should always be generated from a cryptographically secure source of
> +random numbers, either using get_random_bytes or get_random_once:
> +
> +hsiphash_key_t key;
> +get_random_bytes(key, sizeof(key));
> +
> +If you're not deriving your key from here, you're doing it wrong.
> +
> +2. Using the functions
> +
> +There are two variants of the function, one that takes a list of integers, and
> +one that takes a buffer:
> +
> +u32 hsiphash(const void *data, size_t len, siphash_key_t key);
> +
> +And:
> +
> +u32 hsiphash_1u32(u32, hsiphash_key_t key);
> +u32 hsiphash_2u32(u32, u32, hsiphash_key_t key);
> +u32 hsiphash_3u32(u32, u32, u32, hsiphash_key_t key);
> +u32 hsiphash_4u32(u32, u32, u32, u32, hsiphash_key_t key);
> +
> +If you pass the generic hsiphash function something of a constant length, it
> +will constant fold at compile-time and automatically choose one of the
> +optimized functions.
> +
> +3. Hashtable key function usage:
> +
> +struct some_hashtable {
> + DECLARE_HASHTABLE(hashtable, 8);
> + hsiphash_key_t key;
> +};
> +
> +void init_hashtable(struct some_hashtable *table)
> +{
> + get_random_bytes(table->key, sizeof(table->key));
> +}
> +
> +static inline hlist_head *some_hashtable_bucket(struct some_hashtable *table, struct interesting_input *input)
> +{
> + return &table->hashtable[hsiphash(input, sizeof(*input), table->key) & (HASH_SIZE(table->hashtable) - 1)];
> +}
> +
> +You may then iterate like usual over the returned hash bucket.
> +
> +4. Performance
> +
> +HalfSipHash is roughly 3 times slower than JenkinsHash. For many replacements,
> +this will not be a problem, as the hashtable lookup isn't the bottleneck. And
> +in general, this is probably a good sacrifice to make for the security and DoS
> +resistance of HalfSipHash.
> diff --git a/include/linux/siphash.h b/include/linux/siphash.h
> index 7aa666eb00d9..efab44c654f3 100644
> --- a/include/linux/siphash.h
> +++ b/include/linux/siphash.h
> @@ -5,7 +5,9 @@
> * SipHash: a fast short-input PRF
> * https://131002.net/siphash/
> *
> - * This implementation is specifically for SipHash2-4.
> + * This implementation is specifically for SipHash2-4 for a secure PRF
> + * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for
> + * hashtables.
> */
>
> #ifndef _LINUX_SIPHASH_H
> @@ -76,4 +78,56 @@ static inline u64 siphash(const void *data, size_t len, const siphash_key_t key)
> return ___siphash_aligned(data, len, key);
> }
>
> +#if BITS_PER_LONG == 64
> +typedef siphash_key_t hsiphash_key_t;
> +#define HSIPHASH_ALIGNMENT SIPHASH_ALIGNMENT
> +#else
> +typedef u32 hsiphash_key_t[2];
> +#define HSIPHASH_ALIGNMENT __alignof__(u32)
> +#endif
> +
> +u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t key);
> +#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
> +u32 __hsiphash_unaligned(const void *data, size_t len, const hsiphash_key_t key);
> +#endif
> +
> +u32 hsiphash_1u32(const u32 a, const hsiphash_key_t key);
> +u32 hsiphash_2u32(const u32 a, const u32 b, const hsiphash_key_t key);
> +u32 hsiphash_3u32(const u32 a, const u32 b, const u32 c,
> + const hsiphash_key_t key);
> +u32 hsiphash_4u32(const u32 a, const u32 b, const u32 c, const u32 d,
> + const hsiphash_key_t key);
> +
> +static inline u32 ___hsiphash_aligned(const __le32 *data, size_t len, const hsiphash_key_t key)
> +{
> + if (__builtin_constant_p(len) && len == 4)
> + return hsiphash_1u32(le32_to_cpu(data[0]), key);
> + if (__builtin_constant_p(len) && len == 8)
> + return hsiphash_2u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]),
> + key);
> + if (__builtin_constant_p(len) && len == 12)
> + return hsiphash_3u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]),
> + le32_to_cpu(data[2]), key);
> + if (__builtin_constant_p(len) && len == 16)
> + return hsiphash_4u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]),
> + le32_to_cpu(data[2]), le32_to_cpu(data[3]),
> + key);
> + return __hsiphash_aligned(data, len, key);
> +}
> +
> +/**
> + * hsiphash - compute 32-bit hsiphash PRF value
> + * @data: buffer to hash
> + * @size: size of @data
> + * @key: the hsiphash key
> + */
> +static inline u32 hsiphash(const void *data, size_t len, const hsiphash_key_t key)
> +{
> +#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
> + if (!IS_ALIGNED((unsigned long)data, HSIPHASH_ALIGNMENT))
> + return __hsiphash_unaligned(data, len, key);
> +#endif
> + return ___hsiphash_aligned(data, len, key);
> +}
> +
> #endif /* _LINUX_SIPHASH_H */
> diff --git a/lib/siphash.c b/lib/siphash.c
> index ff2151313667..e2481226d96c 100644
> --- a/lib/siphash.c
> +++ b/lib/siphash.c
> @@ -5,7 +5,9 @@
> * SipHash: a fast short-input PRF
> * https://131002.net/siphash/
> *
> - * This implementation is specifically for SipHash2-4.
> + * This implementation is specifically for SipHash2-4 for a secure PRF
> + * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for
> + * hashtables.
> */
>
> #include <linux/siphash.h>
> @@ -230,3 +232,317 @@ u64 siphash_3u32(const u32 first, const u32 second, const u32 third,
> POSTAMBLE
> }
> EXPORT_SYMBOL(siphash_3u32);
> +
> +#if BITS_PER_LONG == 64
> +/* Note that this HalfSipHash1-3 implementation on 64-bit
> + * isn't actually HalfSipHash1-3 but rather SipHash1-3. */
> +
> +#define HSIPROUND SIPROUND
> +#define HPREAMBLE(len) PREAMBLE(len)
> +#define HPOSTAMBLE \
> + v3 ^= b; \
> + HSIPROUND; \
> + v0 ^= b; \
> + v2 ^= 0xff; \
> + HSIPROUND; \
> + HSIPROUND; \
> + HSIPROUND; \
> + return (v0 ^ v1) ^ (v2 ^ v3);
> +
> +u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t key)
> +{
> + const u8 *end = data + len - (len % sizeof(u64));
> + const u8 left = len & (sizeof(u64) - 1);
> + u64 m;
> + HPREAMBLE(len)
> + for (; data != end; data += sizeof(u64)) {
> + m = le64_to_cpup(data);
> + v3 ^= m;
> + HSIPROUND;
> + v0 ^= m;
> + }
> +#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
> + if (left)
> + b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
> + bytemask_from_count(left)));
> +#else
> + switch (left) {
> + case 7: b |= ((u64)end[6]) << 48;
> + case 6: b |= ((u64)end[5]) << 40;
> + case 5: b |= ((u64)end[4]) << 32;
> + case 4: b |= le32_to_cpup(data); break;
> + case 3: b |= ((u64)end[2]) << 16;
> + case 2: b |= le16_to_cpup(data); break;
> + case 1: b |= end[0];
> + }
> +#endif
> + HPOSTAMBLE
> +}
> +EXPORT_SYMBOL(__hsiphash_aligned);
> +
> +#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
> +u32 __hsiphash_unaligned(const void *data, size_t len, const hsiphash_key_t key)
> +{
> + const u8 *end = data + len - (len % sizeof(u64));
> + const u8 left = len & (sizeof(u64) - 1);
> + u64 m;
> + HPREAMBLE(len)
> + for (; data != end; data += sizeof(u64)) {
> + m = get_unaligned_le64(data);
> + v3 ^= m;
> + HSIPROUND;
> + v0 ^= m;
> + }
> +#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
> + if (left)
> + b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
> + bytemask_from_count(left)));
> +#else
> + switch (left) {
> + case 7: b |= ((u64)end[6]) << 48;
> + case 6: b |= ((u64)end[5]) << 40;
> + case 5: b |= ((u64)end[4]) << 32;
> + case 4: b |= get_unaligned_le32(end); break;
> + case 3: b |= ((u64)end[2]) << 16;
> + case 2: b |= get_unaligned_le16(end); break;
> + case 1: b |= end[0];
> + }
> +#endif
> + HPOSTAMBLE
> +}
> +EXPORT_SYMBOL(__hsiphash_unaligned);
> +#endif
> +
> +/**
> + * hsiphash_1u32 - compute 64-bit hsiphash PRF value of a u32
> + * @first: first u32
> + * @key: the hsiphash key
> + */
> +u32 hsiphash_1u32(const u32 first, const hsiphash_key_t key)
> +{
> + HPREAMBLE(4)
> + b |= first;
> + HPOSTAMBLE
> +}
> +EXPORT_SYMBOL(hsiphash_1u32);
> +
> +/**
> + * hsiphash_2u32 - compute 32-bit hsiphash PRF value of 2 u32
> + * @first: first u32
> + * @second: second u32
> + * @key: the hsiphash key
> + */
> +u32 hsiphash_2u32(const u32 first, const u32 second, const hsiphash_key_t key)
> +{
> + u64 combined = (u64)second << 32 | first;
> + HPREAMBLE(8)
> + v3 ^= combined;
> + HSIPROUND;
> + v0 ^= combined;
> + HPOSTAMBLE
> +}
> +EXPORT_SYMBOL(hsiphash_2u32);
> +
> +/**
> + * hsiphash_3u32 - compute 32-bit hsiphash PRF value of 3 u32
> + * @first: first u32
> + * @second: second u32
> + * @third: third u32
> + * @key: the hsiphash key
> + */
> +u32 hsiphash_3u32(const u32 first, const u32 second, const u32 third,
> + const hsiphash_key_t key)
> +{
> + u64 combined = (u64)second << 32 | first;
> + HPREAMBLE(12)
> + v3 ^= combined;
> + HSIPROUND;
> + v0 ^= combined;
> + b |= third;
> + HPOSTAMBLE
> +}
> +EXPORT_SYMBOL(hsiphash_3u32);
> +
> +/**
> + * hsiphash_4u32 - compute 32-bit hsiphash PRF value of 4 u32
> + * @first: first u32
> + * @second: second u32
> + * @third: third u32
> + * @forth: forth u32
> + * @key: the hsiphash key
> + */
> +u32 hsiphash_4u32(const u32 first, const u32 second, const u32 third,
> + const u32 forth, const hsiphash_key_t key)
> +{
> + u64 combined = (u64)second << 32 | first;
> + HPREAMBLE(16)
> + v3 ^= combined;
> + HSIPROUND;
> + v0 ^= combined;
> + combined = (u64)forth << 32 | third;
> + v3 ^= combined;
> + HSIPROUND;
> + v0 ^= combined;
> + HPOSTAMBLE
> +}
> +EXPORT_SYMBOL(hsiphash_4u32);
> +#else
> +#define HSIPROUND \
> + do { \
> + v0 += v1; v1 = rol32(v1, 5); v1 ^= v0; v0 = rol32(v0, 16); \
> + v2 += v3; v3 = rol32(v3, 8); v3 ^= v2; \
> + v0 += v3; v3 = rol32(v3, 7); v3 ^= v0; \
> + v2 += v1; v1 = rol32(v1, 13); v1 ^= v2; v2 = rol32(v2, 16); \
> + } while(0)
> +
> +#define HPREAMBLE(len) \
> + u32 v0 = 0; \
> + u32 v1 = 0; \
> + u32 v2 = 0x6c796765U; \
> + u32 v3 = 0x74656462U; \
> + u32 b = ((u32)len) << 24; \
> + v3 ^= key[1]; \
> + v2 ^= key[0]; \
> + v1 ^= key[1]; \
> + v0 ^= key[0];
> +
> +#define HPOSTAMBLE \
> + v3 ^= b; \
> + HSIPROUND; \
> + v0 ^= b; \
> + v2 ^= 0xff; \
> + HSIPROUND; \
> + HSIPROUND; \
> + HSIPROUND; \
> + return v1 ^ v3;
> +
> +u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t key)
> +{
> + const u8 *end = data + len - (len % sizeof(u32));
> + const u8 left = len & (sizeof(u32) - 1);
> + u32 m;
> + HPREAMBLE(len)
> + for (; data != end; data += sizeof(u32)) {
> + m = le32_to_cpup(data);
> + v3 ^= m;
> + HSIPROUND;
> + v0 ^= m;
> + }
> + switch (left) {
> + case 3: b |= ((u32)end[2]) << 16;
> + case 2: b |= le16_to_cpup(data); break;
> + case 1: b |= end[0];
> + }
> + HPOSTAMBLE
> +}
> +EXPORT_SYMBOL(__hsiphash_aligned);
> +
> +#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
> +u32 __hsiphash_unaligned(const void *data, size_t len, const hsiphash_key_t key)
> +{
> + const u8 *end = data + len - (len % sizeof(u32));
> + const u8 left = len & (sizeof(u32) - 1);
> + u32 m;
> + HPREAMBLE(len)
> + for (; data != end; data += sizeof(u32)) {
> + m = get_unaligned_le32(data);
> + v3 ^= m;
> + HSIPROUND;
> + v0 ^= m;
> + }
> + switch (left) {
> + case 3: b |= ((u32)end[2]) << 16;
> + case 2: b |= get_unaligned_le16(end); break;
> + case 1: b |= end[0];
> + }
> + HPOSTAMBLE
> +}
> +EXPORT_SYMBOL(__hsiphash_unaligned);
> +#endif
> +
> +/**
> + * hsiphash_1u32 - compute 32-bit hsiphash PRF value of a u32
> + * @first: first u32
> + * @key: the hsiphash key
> + */
> +u32 hsiphash_1u32(const u32 first, const hsiphash_key_t key)
> +{
> + HPREAMBLE(4)
> + v3 ^= first;
> + HSIPROUND;
> + v0 ^= first;
> + HPOSTAMBLE
> +}
> +EXPORT_SYMBOL(hsiphash_1u32);
> +
> +/**
> + * hsiphash_2u32 - compute 32-bit hsiphash PRF value of 2 u32
> + * @first: first u32
> + * @second: second u32
> + * @key: the hsiphash key
> + */
> +u32 hsiphash_2u32(const u32 first, const u32 second, const hsiphash_key_t key)
> +{
> + HPREAMBLE(8)
> + v3 ^= first;
> + HSIPROUND;
> + v0 ^= first;
> + v3 ^= second;
> + HSIPROUND;
> + v0 ^= second;
> + HPOSTAMBLE
> +}
> +EXPORT_SYMBOL(hsiphash_2u32);
> +
> +/**
> + * hsiphash_3u32 - compute 32-bit hsiphash PRF value of 3 u32
> + * @first: first u32
> + * @second: second u32
> + * @third: third u32
> + * @key: the hsiphash key
> + */
> +u32 hsiphash_3u32(const u32 first, const u32 second, const u32 third,
> + const hsiphash_key_t key)
> +{
> + HPREAMBLE(12)
> + v3 ^= first;
> + HSIPROUND;
> + v0 ^= first;
> + v3 ^= second;
> + HSIPROUND;
> + v0 ^= second;
> + v3 ^= third;
> + HSIPROUND;
> + v0 ^= third;
> + HPOSTAMBLE
> +}
> +EXPORT_SYMBOL(hsiphash_3u32);
> +
> +/**
> + * hsiphash_4u32 - compute 32-bit hsiphash PRF value of 4 u32
> + * @first: first u32
> + * @second: second u32
> + * @third: third u32
> + * @forth: forth u32
> + * @key: the hsiphash key
> + */
> +u32 hsiphash_4u32(const u32 first, const u32 second, const u32 third,
> + const u32 forth, const hsiphash_key_t key)
> +{
> + HPREAMBLE(16)
> + v3 ^= first;
> + HSIPROUND;
> + v0 ^= first;
> + v3 ^= second;
> + HSIPROUND;
> + v0 ^= second;
> + v3 ^= third;
> + HSIPROUND;
> + v0 ^= third;
> + v3 ^= forth;
> + HSIPROUND;
> + v0 ^= forth;
> + HPOSTAMBLE
> +}
> +EXPORT_SYMBOL(hsiphash_4u32);
> +#endif
> diff --git a/lib/test_siphash.c b/lib/test_siphash.c
> index e0ba2cf8dc67..ac291ec27fb6 100644
> --- a/lib/test_siphash.c
> +++ b/lib/test_siphash.c
> @@ -7,7 +7,9 @@
> * SipHash: a fast short-input PRF
> * https://131002.net/siphash/
> *
> - * This implementation is specifically for SipHash2-4.
> + * This implementation is specifically for SipHash2-4 for a secure PRF
> + * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for
> + * hashtables.
> */
>
> #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> @@ -18,10 +20,16 @@
> #include <linux/errno.h>
> #include <linux/module.h>
>
> -/* Test vectors taken from official reference source available at:
> - * https://131002.net/siphash/siphash24.c
> +/* Test vectors taken from reference source available at:
> + * https://github.com/veorq/SipHash
> */
> -static const u64 test_vectors[64] = {
> +
> +
> +
> +static const siphash_key_t test_key_siphash =
> + { 0x0706050403020100ULL , 0x0f0e0d0c0b0a0908ULL };
> +
> +static const u64 test_vectors_siphash[64] = {
> 0x726fdb47dd0e0e31ULL, 0x74f839c593dc67fdULL, 0x0d6c8009d9a94f5aULL,
> 0x85676696d7fb7e2dULL, 0xcf2794e0277187b7ULL, 0x18765564cd99a68dULL,
> 0xcbc9466e58fee3ceULL, 0xab0200f58b01d137ULL, 0x93f5f5799a932462ULL,
> @@ -45,9 +53,64 @@ static const u64 test_vectors[64] = {
> 0x6ca4ecb15c5f91e1ULL, 0x9f626da15c9625f3ULL, 0xe51b38608ef25f57ULL,
> 0x958a324ceb064572ULL
> };
> -static const siphash_key_t test_key =
> +#if BITS_PER_LONG == 64
> +static const hsiphash_key_t test_key_hsiphash =
> { 0x0706050403020100ULL , 0x0f0e0d0c0b0a0908ULL };
>
> +static const u32 test_vectors_hsiphash[64] = {
> + 0x050fc4dcU, 0x7d57ca93U, 0x4dc7d44dU,
> + 0xe7ddf7fbU, 0x88d38328U, 0x49533b67U,
> + 0xc59f22a7U, 0x9bb11140U, 0x8d299a8eU,
> + 0x6c063de4U, 0x92ff097fU, 0xf94dc352U,
> + 0x57b4d9a2U, 0x1229ffa7U, 0xc0f95d34U,
> + 0x2a519956U, 0x7d908b66U, 0x63dbd80cU,
> + 0xb473e63eU, 0x8d297d1cU, 0xa6cce040U,
> + 0x2b45f844U, 0xa320872eU, 0xdae6c123U,
> + 0x67349c8cU, 0x705b0979U, 0xca9913a5U,
> + 0x4ade3b35U, 0xef6cd00dU, 0x4ab1e1f4U,
> + 0x43c5e663U, 0x8c21d1bcU, 0x16a7b60dU,
> + 0x7a8ff9bfU, 0x1f2a753eU, 0xbf186b91U,
> + 0xada26206U, 0xa3c33057U, 0xae3a36a1U,
> + 0x7b108392U, 0x99e41531U, 0x3f1ad944U,
> + 0xc8138825U, 0xc28949a6U, 0xfaf8876bU,
> + 0x9f042196U, 0x68b1d623U, 0x8b5114fdU,
> + 0xdf074c46U, 0x12cc86b3U, 0x0a52098fU,
> + 0x9d292f9aU, 0xa2f41f12U, 0x43a71ed0U,
> + 0x73f0bce6U, 0x70a7e980U, 0x243c6d75U,
> + 0xfdb71513U, 0xa67d8a08U, 0xb7e8f148U,
> + 0xf7a644eeU, 0x0f1837f2U, 0x4b6694e0U,
> + 0xb7bbb3a8U
> +};
> +#else
> +static const hsiphash_key_t test_key_hsiphash =
> + { 0x03020100U, 0x07060504U };
> +
> +static const u32 test_vectors_hsiphash[64] = {
> + 0x5814c896U, 0xe7e864caU, 0xbc4b0e30U,
> + 0x01539939U, 0x7e059ea6U, 0x88e3d89bU,
> + 0xa0080b65U, 0x9d38d9d6U, 0x577999b1U,
> + 0xc839caedU, 0xe4fa32cfU, 0x959246eeU,
> + 0x6b28096cU, 0x66dd9cd6U, 0x16658a7cU,
> + 0xd0257b04U, 0x8b31d501U, 0x2b1cd04bU,
> + 0x06712339U, 0x522aca67U, 0x911bb605U,
> + 0x90a65f0eU, 0xf826ef7bU, 0x62512debU,
> + 0x57150ad7U, 0x5d473507U, 0x1ec47442U,
> + 0xab64afd3U, 0x0a4100d0U, 0x6d2ce652U,
> + 0x2331b6a3U, 0x08d8791aU, 0xbc6dda8dU,
> + 0xe0f6c934U, 0xb0652033U, 0x9b9851ccU,
> + 0x7c46fb7fU, 0x732ba8cbU, 0xf142997aU,
> + 0xfcc9aa1bU, 0x05327eb2U, 0xe110131cU,
> + 0xf9e5e7c0U, 0xa7d708a6U, 0x11795ab1U,
> + 0x65671619U, 0x9f5fff91U, 0xd89c5267U,
> + 0x007783ebU, 0x95766243U, 0xab639262U,
> + 0x9c7e1390U, 0xc368dda6U, 0x38ddc455U,
> + 0xfa13d379U, 0x979ea4e8U, 0x53ecd77eU,
> + 0x2ee80657U, 0x33dbb66aU, 0xae3f0577U,
> + 0x88b4c4ccU, 0x3e7f480bU, 0x74c1ebf8U,
> + 0x87178304U
> +};
> +#endif
> +
> static int __init siphash_test_init(void)
> {
> u8 in[64] __aligned(SIPHASH_ALIGNMENT);
> @@ -58,49 +121,75 @@ static int __init siphash_test_init(void)
> for (i = 0; i < 64; ++i) {
> in[i] = i;
> in_unaligned[i + 1] = i;
> - if (siphash(in, i, test_key) != test_vectors[i]) {
> - pr_info("self-test aligned %u: FAIL\n", i + 1);
> + if (siphash(in, i, test_key_siphash) != test_vectors_siphash[i]) {
> + pr_info("siphash self-test aligned %u: FAIL\n", i + 1);
> + ret = -EINVAL;
> + }
> + if (siphash(in_unaligned + 1, i, test_key_siphash) != test_vectors_siphash[i]) {
> + pr_info("siphash self-test unaligned %u: FAIL\n", i + 1);
> ret = -EINVAL;
> }
> - if (siphash(in_unaligned + 1, i, test_key) != test_vectors[i]) {
> - pr_info("self-test unaligned %u: FAIL\n", i + 1);
> + if (hsiphash(in, i, test_key_hsiphash) != test_vectors_hsiphash[i]) {
> + pr_info("hsiphash self-test aligned %u: FAIL\n", i + 1);
> + ret = -EINVAL;
> + }
> + if (hsiphash(in_unaligned + 1, i, test_key_hsiphash) != test_vectors_hsiphash[i]) {
> + pr_info("hsiphash self-test unaligned %u: FAIL\n", i + 1);
> ret = -EINVAL;
> }
> }
> - if (siphash_1u64(0x0706050403020100ULL, test_key) != test_vectors[8]) {
> - pr_info("self-test 1u64: FAIL\n");
> + if (siphash_1u64(0x0706050403020100ULL, test_key_siphash) != test_vectors_siphash[8]) {
> + pr_info("siphash self-test 1u64: FAIL\n");
> ret = -EINVAL;
> }
> - if (siphash_2u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL, test_key) != test_vectors[16]) {
> - pr_info("self-test 2u64: FAIL\n");
> + if (siphash_2u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL, test_key_siphash) != test_vectors_siphash[16]) {
> + pr_info("siphash self-test 2u64: FAIL\n");
> ret = -EINVAL;
> }
> if (siphash_3u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL,
> - 0x1716151413121110ULL, test_key) != test_vectors[24]) {
> - pr_info("self-test 3u64: FAIL\n");
> + 0x1716151413121110ULL, test_key_siphash) != test_vectors_siphash[24]) {
> + pr_info("siphash self-test 3u64: FAIL\n");
> ret = -EINVAL;
> }
> if (siphash_4u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL,
> - 0x1716151413121110ULL, 0x1f1e1d1c1b1a1918ULL, test_key) != test_vectors[32]) {
> - pr_info("self-test 4u64: FAIL\n");
> + 0x1716151413121110ULL, 0x1f1e1d1c1b1a1918ULL, test_key_siphash) != test_vectors_siphash[32]) {
> + pr_info("siphash self-test 4u64: FAIL\n");
> ret = -EINVAL;
> }
> - if (siphash_1u32(0x03020100U, test_key) != test_vectors[4]) {
> - pr_info("self-test 1u32: FAIL\n");
> + if (siphash_1u32(0x03020100U, test_key_siphash) != test_vectors_siphash[4]) {
> + pr_info("siphash self-test 1u32: FAIL\n");
> ret = -EINVAL;
> }
> - if (siphash_2u32(0x03020100U, 0x07060504U, test_key) != test_vectors[8]) {
> - pr_info("self-test 2u32: FAIL\n");
> + if (siphash_2u32(0x03020100U, 0x07060504U, test_key_siphash) != test_vectors_siphash[8]) {
> + pr_info("siphash self-test 2u32: FAIL\n");
> ret = -EINVAL;
> }
> if (siphash_3u32(0x03020100U, 0x07060504U,
> - 0x0b0a0908U, test_key) != test_vectors[12]) {
> - pr_info("self-test 3u32: FAIL\n");
> + 0x0b0a0908U, test_key_siphash) != test_vectors_siphash[12]) {
> + pr_info("siphash self-test 3u32: FAIL\n");
> ret = -EINVAL;
> }
> if (siphash_4u32(0x03020100U, 0x07060504U,
> - 0x0b0a0908U, 0x0f0e0d0cU, test_key) != test_vectors[16]) {
> - pr_info("self-test 4u32: FAIL\n");
> + 0x0b0a0908U, 0x0f0e0d0cU, test_key_siphash) != test_vectors_siphash[16]) {
> + pr_info("siphash self-test 4u32: FAIL\n");
> + ret = -EINVAL;
> + }
> + if (hsiphash_1u32(0x03020100U, test_key_hsiphash) != test_vectors_hsiphash[4]) {
> + pr_info("hsiphash self-test 1u32: FAIL\n");
> + ret = -EINVAL;
> + }
> + if (hsiphash_2u32(0x03020100U, 0x07060504U, test_key_hsiphash) != test_vectors_hsiphash[8]) {
> + pr_info("hsiphash self-test 2u32: FAIL\n");
> + ret = -EINVAL;
> + }
> + if (hsiphash_3u32(0x03020100U, 0x07060504U,
> + 0x0b0a0908U, test_key_hsiphash) != test_vectors_hsiphash[12]) {
> + pr_info("hsiphash self-test 3u32: FAIL\n");
> + ret = -EINVAL;
> + }
> + if (hsiphash_4u32(0x03020100U, 0x07060504U,
> + 0x0b0a0908U, 0x0f0e0d0cU, test_key_hsiphash) != test_vectors_hsiphash[16]) {
> + pr_info("hsiphash self-test 4u32: FAIL\n");
> ret = -EINVAL;
> }
> if (!ret)
> --
> 2.11.0
>
Looks good to me (co-designer of SipHash).
Reviewed-by: Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
^ permalink raw reply
* Re: [PATCH net] amd-xgbe: Fix IRQ processing when running in single IRQ mode
From: David Miller @ 2017-01-06 20:34 UTC (permalink / raw)
To: thomas.lendacky; +Cc: netdev
In-Reply-To: <20170104210716.8401.99717.stgit@tlendack-t1.amdoffice.net>
From: Tom Lendacky <thomas.lendacky@amd.com>
Date: Wed, 4 Jan 2017 15:07:16 -0600
> When running in single IRQ mode, the additional IRQ routines were being
> skipped because only the XGMAC interrupt status was being checked.
> Update the code so that the additional IRQ routines are checked whenever
> an interrupt is received.
>
> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Applied.
^ permalink raw reply
* Re: [PATCH] sh_eth: fix EESIPR values for SH77{34|63}
From: David Miller @ 2017-01-06 20:35 UTC (permalink / raw)
To: sergei.shtylyov; +Cc: netdev, linux-renesas-soc
In-Reply-To: <1819012.0ROIJmx7mp@wasted.cogentembedded.com>
From: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
Date: Wed, 04 Jan 2017 22:18:24 +0300
> As the SH77{34|63} manuals are freely available, I've checked the EESIPR
> values written against the manuals, and they appeared to set the reserved
> bits 11-15 (which should be 0 on write). Fix those EESIPR values.
>
> Fixes: 380af9e390ec ("net: sh_eth: CPU dependency code collect to "struct sh_eth_cpu_data"")
> Fixes: f5d12767c8fd ("sh_eth: get SH77{34|63} support out of #ifdef")
> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
Applied.
^ permalink raw reply
* Re: [PATCH] sh_eth: R8A7740 supports packet shecksumming
From: David Miller @ 2017-01-06 20:35 UTC (permalink / raw)
To: sergei.shtylyov; +Cc: netdev, linux-renesas-soc
In-Reply-To: <1871204.P0zXJRoIfd@wasted.cogentembedded.com>
From: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
Date: Thu, 05 Jan 2017 00:29:32 +0300
> The R8A7740 GEther controller supports the packet checksum offloading
> but the 'hw_crc' (bad name, I'll fix it) flag isn't set in the R8A7740
> data, thus CSMR isn't cleared...
>
> Fixes: 73a0d907301e ("net: sh_eth: add support R8A7740")
> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
Applied.
^ permalink raw reply
* Re: [PATCH] sh_eth: R8A7740 supports packet shecksumming
From: David Miller @ 2017-01-06 20:35 UTC (permalink / raw)
To: sergei.shtylyov; +Cc: netdev, linux-renesas-soc
In-Reply-To: <9109092d-f781-1177-12f1-de9edda07f69@cogentembedded.com>
From: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
Date: Thu, 5 Jan 2017 12:33:21 +0300
> Oops, typo in the subject, "shecksumming". David, should I resend?
I accidently pushed this out without fixing the typo, sorry about
that but that's going to be how it is I'm afraid :-)
^ permalink raw reply
* [net-next v1 0/8] netcp: enhancements and minor fixes
From: Murali Karicheri @ 2017-01-06 20:37 UTC (permalink / raw)
To: davem, arnd, netdev, linux-kernel, mugunthanvnm, linux-omap,
grygorii.strashko
This series is for net-next. This propagates enhancements and minor
bug fixes from internal version of the driver to keep the upstream
in sync. Please review and apply if this looks good.
Tested on all of K2HK/E/L boards with nfs rootfs.
Test logs below
K2HK-EVM: http://pastebin.ubuntu.com/23754106/
k2L-EVM: http://pastebin.ubuntu.com/23754143/
K2E-EVM: http://pastebin.ubuntu.com/23754159/
History:
v1 - dropped 1/10 amd 2/10 of v0 based on comments from Rob as
it needs more work before submission
v0 - Initial version
Michael Scherban (1):
net: netcp: store network statistics in 64 bits
Murali Karicheri (7):
net: netcp: extract eflag from desc for rx_hook handling
net: netcp: remove the redundant memmov()
net: netcp: ethss: get phy-handle only if link interface is MAC-to-PHY
net: netcp: use hw capability to remove FCS word from rx packets
net: netcp: ale: update to support unknown vlan controls for NU switch
net: netcp: ale: use ale_status to size the ale table
net: netcp: ale: add proper ale entry mask bits for netcp switch ALE
drivers/net/ethernet/ti/cpsw_ale.c | 180 +++++++++++++++++++++++++++++-----
drivers/net/ethernet/ti/cpsw_ale.h | 17 +++-
drivers/net/ethernet/ti/netcp.h | 21 ++++
drivers/net/ethernet/ti/netcp_core.c | 102 +++++++++++++++----
drivers/net/ethernet/ti/netcp_ethss.c | 23 +++--
include/linux/soc/ti/knav_dma.h | 2 +
6 files changed, 292 insertions(+), 53 deletions(-)
--
1.9.1
^ permalink raw reply
* [net-next v1 2/8] net: netcp: remove the redundant memmov()
From: Murali Karicheri @ 2017-01-06 20:37 UTC (permalink / raw)
To: davem, arnd, netdev, linux-kernel, mugunthanvnm, linux-omap,
grygorii.strashko
In-Reply-To: <1483735066-14632-1-git-send-email-m-karicheri2@ti.com>
The psdata is populated with command data by netcp modules
to the tail of the buffer and set_words() copy the same
to the front of the psdata. So remove the redundant memmov
function call.
Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
---
drivers/net/ethernet/ti/netcp_core.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c
index a136c56..286fd8d 100644
--- a/drivers/net/ethernet/ti/netcp_core.c
+++ b/drivers/net/ethernet/ti/netcp_core.c
@@ -1226,9 +1226,9 @@ static int netcp_tx_submit_skb(struct netcp_intf *netcp,
/* psdata points to both native-endian and device-endian data */
__le32 *psdata = (void __force *)p_info.psdata;
- memmove(p_info.psdata, p_info.psdata + p_info.psdata_len,
- p_info.psdata_len);
- set_words(p_info.psdata, p_info.psdata_len, psdata);
+ set_words((u32 *)psdata +
+ (KNAV_DMA_NUM_PS_WORDS - p_info.psdata_len),
+ p_info.psdata_len, psdata);
tmp |= (p_info.psdata_len & KNAV_DMA_DESC_PSLEN_MASK) <<
KNAV_DMA_DESC_PSLEN_SHIFT;
}
--
1.9.1
^ permalink raw reply related
* [net-next v1 8/8] net: netcp: ale: add proper ale entry mask bits for netcp switch ALE
From: Murali Karicheri @ 2017-01-06 20:37 UTC (permalink / raw)
To: davem, arnd, netdev, linux-kernel, mugunthanvnm, linux-omap,
grygorii.strashko
In-Reply-To: <1483735066-14632-1-git-send-email-m-karicheri2@ti.com>
For NetCP NU Switch ALE, some of the mask bits are different than
defaults used in the driver. Add a new macro DEFINE_ALE_FIELD1 that use
a configurable mask bits and use it in the driver. These bits are set to
correct values by using the new variables added to cpsw_ale structure
and re-used in the macros. The parameter nu_switch_ale is configured by
the caller driver to indicate the ALE is for that switch and is used in
the ALE driver to do customization as needed.
Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
---
drivers/net/ethernet/ti/cpsw_ale.c | 99 ++++++++++++++++++++++++++++++--------
drivers/net/ethernet/ti/cpsw_ale.h | 4 ++
2 files changed, 84 insertions(+), 19 deletions(-)
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index 62a18d6..ddd43e0 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -29,6 +29,7 @@
#define ALE_VERSION_MAJOR(rev, mask) (((rev) >> 8) & (mask))
#define ALE_VERSION_MINOR(rev) (rev & 0xff)
+#define ALE_VERSION_1R3 0x0103
#define ALE_VERSION_1R4 0x0104
/* ALE Registers */
@@ -46,6 +47,7 @@
#define ALE_UNKNOWNVLAN_UNREG_MCAST_FLOOD 0x94
#define ALE_UNKNOWNVLAN_REG_MCAST_FLOOD 0x98
#define ALE_UNKNOWNVLAN_FORCE_UNTAG_EGRESS 0x9C
+#define ALE_VLAN_MASK_MUX(reg) (0xc0 + (0x4 * (reg)))
#define ALE_TABLE_WRITE BIT(31)
@@ -96,20 +98,34 @@ static inline void cpsw_ale_set_field(u32 *ale_entry, u32 start, u32 bits,
cpsw_ale_set_field(ale_entry, start, bits, value); \
}
+#define DEFINE_ALE_FIELD1(name, start) \
+static inline int cpsw_ale_get_##name(u32 *ale_entry, u32 bits) \
+{ \
+ return cpsw_ale_get_field(ale_entry, start, bits); \
+} \
+static inline void cpsw_ale_set_##name(u32 *ale_entry, u32 value, \
+ u32 bits) \
+{ \
+ cpsw_ale_set_field(ale_entry, start, bits, value); \
+}
+
DEFINE_ALE_FIELD(entry_type, 60, 2)
DEFINE_ALE_FIELD(vlan_id, 48, 12)
DEFINE_ALE_FIELD(mcast_state, 62, 2)
-DEFINE_ALE_FIELD(port_mask, 66, 3)
+DEFINE_ALE_FIELD1(port_mask, 66)
DEFINE_ALE_FIELD(super, 65, 1)
DEFINE_ALE_FIELD(ucast_type, 62, 2)
-DEFINE_ALE_FIELD(port_num, 66, 2)
+DEFINE_ALE_FIELD1(port_num, 66)
DEFINE_ALE_FIELD(blocked, 65, 1)
DEFINE_ALE_FIELD(secure, 64, 1)
-DEFINE_ALE_FIELD(vlan_untag_force, 24, 3)
-DEFINE_ALE_FIELD(vlan_reg_mcast, 16, 3)
-DEFINE_ALE_FIELD(vlan_unreg_mcast, 8, 3)
-DEFINE_ALE_FIELD(vlan_member_list, 0, 3)
+DEFINE_ALE_FIELD1(vlan_untag_force, 24)
+DEFINE_ALE_FIELD1(vlan_reg_mcast, 16)
+DEFINE_ALE_FIELD1(vlan_unreg_mcast, 8)
+DEFINE_ALE_FIELD1(vlan_member_list, 0)
DEFINE_ALE_FIELD(mcast, 40, 1)
+/* ALE NetCP nu switch specific */
+DEFINE_ALE_FIELD(vlan_unreg_mcast_idx, 20, 3)
+DEFINE_ALE_FIELD(vlan_reg_mcast_idx, 44, 3)
/* The MAC address field in the ALE entry cannot be macroized as above */
static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr)
@@ -235,14 +251,16 @@ static void cpsw_ale_flush_mcast(struct cpsw_ale *ale, u32 *ale_entry,
{
int mask;
- mask = cpsw_ale_get_port_mask(ale_entry);
+ mask = cpsw_ale_get_port_mask(ale_entry,
+ ale->port_mask_bits);
if ((mask & port_mask) == 0)
return; /* ports dont intersect, not interested */
mask &= ~port_mask;
/* free if only remaining port is host port */
if (mask)
- cpsw_ale_set_port_mask(ale_entry, mask);
+ cpsw_ale_set_port_mask(ale_entry, mask,
+ ale->port_mask_bits);
else
cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
}
@@ -303,7 +321,7 @@ int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT);
cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0);
cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
- cpsw_ale_set_port_num(ale_entry, port);
+ cpsw_ale_set_port_num(ale_entry, port, ale->port_num_bits);
idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
if (idx < 0)
@@ -350,9 +368,11 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
cpsw_ale_set_super(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
cpsw_ale_set_mcast_state(ale_entry, mcast_state);
- mask = cpsw_ale_get_port_mask(ale_entry);
+ mask = cpsw_ale_get_port_mask(ale_entry,
+ ale->port_mask_bits);
port_mask |= mask;
- cpsw_ale_set_port_mask(ale_entry, port_mask);
+ cpsw_ale_set_port_mask(ale_entry, port_mask,
+ ale->port_mask_bits);
if (idx < 0)
idx = cpsw_ale_match_free(ale);
@@ -379,7 +399,8 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
cpsw_ale_read(ale, idx, ale_entry);
if (port_mask)
- cpsw_ale_set_port_mask(ale_entry, port_mask);
+ cpsw_ale_set_port_mask(ale_entry, port_mask,
+ ale->port_mask_bits);
else
cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
@@ -388,6 +409,21 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
}
EXPORT_SYMBOL_GPL(cpsw_ale_del_mcast);
+/* ALE NetCP NU switch specific vlan functions */
+static void cpsw_ale_set_vlan_mcast(struct cpsw_ale *ale, u32 *ale_entry,
+ int reg_mcast, int unreg_mcast)
+{
+ int idx;
+
+ /* Set VLAN registered multicast flood mask */
+ idx = cpsw_ale_get_vlan_reg_mcast_idx(ale_entry);
+ writel(reg_mcast, ale->params.ale_regs + ALE_VLAN_MASK_MUX(idx));
+
+ /* Set VLAN unregistered multicast flood mask */
+ idx = cpsw_ale_get_vlan_unreg_mcast_idx(ale_entry);
+ writel(unreg_mcast, ale->params.ale_regs + ALE_VLAN_MASK_MUX(idx));
+}
+
int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
int reg_mcast, int unreg_mcast)
{
@@ -401,10 +437,16 @@ int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN);
cpsw_ale_set_vlan_id(ale_entry, vid);
- cpsw_ale_set_vlan_untag_force(ale_entry, untag);
- cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast);
- cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast);
- cpsw_ale_set_vlan_member_list(ale_entry, port);
+ cpsw_ale_set_vlan_untag_force(ale_entry, untag, ale->vlan_field_bits);
+ if (!ale->params.nu_switch_ale) {
+ cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast,
+ ale->vlan_field_bits);
+ cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast,
+ ale->vlan_field_bits);
+ } else {
+ cpsw_ale_set_vlan_mcast(ale, ale_entry, reg_mcast, unreg_mcast);
+ }
+ cpsw_ale_set_vlan_member_list(ale_entry, port, ale->vlan_field_bits);
if (idx < 0)
idx = cpsw_ale_match_free(ale);
@@ -430,7 +472,8 @@ int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
cpsw_ale_read(ale, idx, ale_entry);
if (port_mask)
- cpsw_ale_set_vlan_member_list(ale_entry, port_mask);
+ cpsw_ale_set_vlan_member_list(ale_entry, port_mask,
+ ale->vlan_field_bits);
else
cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
@@ -458,12 +501,15 @@ void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti)
if (type != ALE_TYPE_VLAN)
continue;
- unreg_mcast = cpsw_ale_get_vlan_unreg_mcast(ale_entry);
+ unreg_mcast =
+ cpsw_ale_get_vlan_unreg_mcast(ale_entry,
+ ale->vlan_field_bits);
if (allmulti)
unreg_mcast |= 1;
else
unreg_mcast &= ~1;
- cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast);
+ cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast,
+ ale->vlan_field_bits);
cpsw_ale_write(ale, idx, ale_entry);
}
}
@@ -769,6 +815,14 @@ void cpsw_ale_start(struct cpsw_ale *ale)
dev_info(ale->params.dev,
"ALE Table size %ld\n", ale->params.ale_entries);
+ /* set default bits for existing h/w */
+ ale->port_mask_bits = 3;
+ ale->port_num_bits = 2;
+ ale->vlan_field_bits = 3;
+
+ /* Set defaults override for ALE on NetCP NU switch and for version
+ * 1R3
+ */
if (ale->params.nu_switch_ale) {
/* Separate registers for unknown vlan configuration.
* Also there are N bits, where N is number of ale
@@ -793,6 +847,13 @@ void cpsw_ale_start(struct cpsw_ale *ale)
ale_controls[ALE_PORT_UNTAGGED_EGRESS].shift = 0;
ale_controls[ALE_PORT_UNTAGGED_EGRESS].offset =
ALE_UNKNOWNVLAN_FORCE_UNTAG_EGRESS;
+ ale->port_mask_bits = ale->params.ale_ports;
+ ale->port_num_bits = ale->params.ale_ports - 1;
+ ale->vlan_field_bits = ale->params.ale_ports;
+ } else if (ale->version == ALE_VERSION_1R3) {
+ ale->port_mask_bits = ale->params.ale_ports;
+ ale->port_num_bits = 3;
+ ale->vlan_field_bits = ale->params.ale_ports;
}
cpsw_ale_control_set(ale, 0, ALE_ENABLE, 1);
diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h
index b1c7954..25d24e8 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.h
+++ b/drivers/net/ethernet/ti/cpsw_ale.h
@@ -39,6 +39,10 @@ struct cpsw_ale {
unsigned long ageout;
int allmulti;
u32 version;
+ /* These bits are different on NetCP NU Switch ALE */
+ u32 port_mask_bits;
+ u32 port_num_bits;
+ u32 vlan_field_bits;
};
enum cpsw_ale_control {
--
1.9.1
^ permalink raw reply related
* [net-next v1 1/8] net: netcp: extract eflag from desc for rx_hook handling
From: Murali Karicheri @ 2017-01-06 20:37 UTC (permalink / raw)
To: davem, arnd, netdev, linux-kernel, mugunthanvnm, linux-omap,
grygorii.strashko
In-Reply-To: <1483735066-14632-1-git-send-email-m-karicheri2@ti.com>
Extract the eflag bits from the received desc and pass it down
the rx_hook chain to be available for netcp modules. Also the
psdata and epib data has to be inspected by the netcp modules.
So the desc can be freed only after returning from the rx_hook.
So move knav_pool_desc_put() after the rx_hook processing.
Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
---
drivers/net/ethernet/ti/netcp.h | 1 +
drivers/net/ethernet/ti/netcp_core.c | 20 +++++++++++++++++---
include/linux/soc/ti/knav_dma.h | 2 ++
3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/ti/netcp.h b/drivers/net/ethernet/ti/netcp.h
index 0f58c58..a92abd6 100644
--- a/drivers/net/ethernet/ti/netcp.h
+++ b/drivers/net/ethernet/ti/netcp.h
@@ -115,6 +115,7 @@ struct netcp_packet {
struct sk_buff *skb;
__le32 *epib;
u32 *psdata;
+ u32 eflags;
unsigned int psdata_len;
struct netcp_intf *netcp;
struct netcp_tx_pipe *tx_pipe;
diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c
index c243335..a136c56 100644
--- a/drivers/net/ethernet/ti/netcp_core.c
+++ b/drivers/net/ethernet/ti/netcp_core.c
@@ -122,6 +122,13 @@ static void get_pkt_info(dma_addr_t *buff, u32 *buff_len, dma_addr_t *ndesc,
*ndesc = le32_to_cpu(desc->next_desc);
}
+static void get_desc_info(u32 *desc_info, u32 *pkt_info,
+ struct knav_dma_desc *desc)
+{
+ *desc_info = le32_to_cpu(desc->desc_info);
+ *pkt_info = le32_to_cpu(desc->packet_info);
+}
+
static u32 get_sw_data(int index, struct knav_dma_desc *desc)
{
/* No Endian conversion needed as this data is untouched by hw */
@@ -653,6 +660,7 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
struct netcp_packet p_info;
struct sk_buff *skb;
void *org_buf_ptr;
+ u32 tmp;
dma_desc = knav_queue_pop(netcp->rx_queue, &dma_sz);
if (!dma_desc)
@@ -724,9 +732,6 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
knav_pool_desc_put(netcp->rx_pool, ndesc);
}
- /* Free the primary descriptor */
- knav_pool_desc_put(netcp->rx_pool, desc);
-
/* check for packet len and warn */
if (unlikely(pkt_sz != accum_sz))
dev_dbg(netcp->ndev_dev, "mismatch in packet size(%d) & sum of fragments(%d)\n",
@@ -739,6 +744,11 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
p_info.skb = skb;
skb->dev = netcp->ndev;
p_info.rxtstamp_complete = false;
+ get_desc_info(&tmp, &p_info.eflags, desc);
+ p_info.epib = desc->epib;
+ p_info.psdata = (u32 __force *)desc->psdata;
+ p_info.eflags = ((p_info.eflags >> KNAV_DMA_DESC_EFLAGS_SHIFT) &
+ KNAV_DMA_DESC_EFLAGS_MASK);
list_for_each_entry(rx_hook, &netcp->rxhook_list_head, list) {
int ret;
@@ -748,10 +758,14 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
dev_err(netcp->ndev_dev, "RX hook %d failed: %d\n",
rx_hook->order, ret);
netcp->ndev->stats.rx_errors++;
+ /* Free the primary descriptor */
+ knav_pool_desc_put(netcp->rx_pool, desc);
dev_kfree_skb(skb);
return 0;
}
}
+ /* Free the primary descriptor */
+ knav_pool_desc_put(netcp->rx_pool, desc);
netcp->ndev->stats.rx_packets++;
netcp->ndev->stats.rx_bytes += skb->len;
diff --git a/include/linux/soc/ti/knav_dma.h b/include/linux/soc/ti/knav_dma.h
index 35cb926..2b78826 100644
--- a/include/linux/soc/ti/knav_dma.h
+++ b/include/linux/soc/ti/knav_dma.h
@@ -41,6 +41,8 @@
#define KNAV_DMA_DESC_RETQ_SHIFT 0
#define KNAV_DMA_DESC_RETQ_MASK MASK(14)
#define KNAV_DMA_DESC_BUF_LEN_MASK MASK(22)
+#define KNAV_DMA_DESC_EFLAGS_MASK MASK(4)
+#define KNAV_DMA_DESC_EFLAGS_SHIFT 20
#define KNAV_DMA_NUM_EPIB_WORDS 4
#define KNAV_DMA_NUM_PS_WORDS 16
--
1.9.1
^ permalink raw reply related
* [net-next v1 4/8] net: netcp: ethss: get phy-handle only if link interface is MAC-to-PHY
From: Murali Karicheri @ 2017-01-06 20:37 UTC (permalink / raw)
To: davem, arnd, netdev, linux-kernel, mugunthanvnm, linux-omap,
grygorii.strashko
In-Reply-To: <1483735066-14632-1-git-send-email-m-karicheri2@ti.com>
Currently to parse phy-handle, driver doesn't check if the interface is
MAC to PHY. This patch add this check for all MAC to PHY interface types
supported by the driver.
Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
---
drivers/net/ethernet/ti/netcp_ethss.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c
index 7d9e36f..4a64b3e 100644
--- a/drivers/net/ethernet/ti/netcp_ethss.c
+++ b/drivers/net/ethernet/ti/netcp_ethss.c
@@ -2930,7 +2930,9 @@ static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave,
}
slave->open = false;
- slave->phy_node = of_parse_phandle(node, "phy-handle", 0);
+ if ((slave->link_interface == SGMII_LINK_MAC_PHY) ||
+ (slave->link_interface == XGMII_LINK_MAC_PHY))
+ slave->phy_node = of_parse_phandle(node, "phy-handle", 0);
slave->port_num = gbe_get_slave_port(gbe_dev, slave->slave_num);
if (slave->link_interface >= XGMII_LINK_MAC_PHY)
--
1.9.1
^ permalink raw reply related
* [net-next v1 3/8] net: netcp: store network statistics in 64 bits
From: Murali Karicheri @ 2017-01-06 20:37 UTC (permalink / raw)
To: davem, arnd, netdev, linux-kernel, mugunthanvnm, linux-omap,
grygorii.strashko
In-Reply-To: <1483735066-14632-1-git-send-email-m-karicheri2@ti.com>
From: Michael Scherban <m-scherban@ti.com>
Previously the network statistics were stored in 32 bit variable
which can cause some stats to roll over after several minutes of
high traffic. This implements 64 bit storage so larger numbers
can be stored.
Signed-off-by: Michael Scherban <m-scherban@ti.com>
Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
---
drivers/net/ethernet/ti/netcp.h | 18 ++++++++++
drivers/net/ethernet/ti/netcp_core.c | 68 +++++++++++++++++++++++++++++-------
2 files changed, 74 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/ti/netcp.h b/drivers/net/ethernet/ti/netcp.h
index a92abd6..d243c5d 100644
--- a/drivers/net/ethernet/ti/netcp.h
+++ b/drivers/net/ethernet/ti/netcp.h
@@ -23,6 +23,7 @@
#include <linux/netdevice.h>
#include <linux/soc/ti/knav_dma.h>
+#include <linux/u64_stats_sync.h>
/* Maximum Ethernet frame size supported by Keystone switch */
#define NETCP_MAX_FRAME_SIZE 9504
@@ -68,6 +69,20 @@ struct netcp_addr {
struct list_head node;
};
+struct netcp_stats {
+ struct u64_stats_sync syncp_rx ____cacheline_aligned_in_smp;
+ u64 rx_packets;
+ u64 rx_bytes;
+ u32 rx_errors;
+ u32 rx_dropped;
+
+ struct u64_stats_sync syncp_tx ____cacheline_aligned_in_smp;
+ u64 tx_packets;
+ u64 tx_bytes;
+ u32 tx_errors;
+ u32 tx_dropped;
+};
+
struct netcp_intf {
struct device *dev;
struct device *ndev_dev;
@@ -88,6 +103,9 @@ struct netcp_intf {
struct napi_struct rx_napi;
struct napi_struct tx_napi;
+ /* 64-bit netcp stats */
+ struct netcp_stats stats;
+
void *rx_channel;
const char *dma_chan_name;
u32 rx_pool_size;
diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c
index 286fd8d..b077ed4 100644
--- a/drivers/net/ethernet/ti/netcp_core.c
+++ b/drivers/net/ethernet/ti/netcp_core.c
@@ -629,6 +629,7 @@ static void netcp_free_rx_desc_chain(struct netcp_intf *netcp,
static void netcp_empty_rx_queue(struct netcp_intf *netcp)
{
+ struct netcp_stats *rx_stats = &netcp->stats;
struct knav_dma_desc *desc;
unsigned int dma_sz;
dma_addr_t dma;
@@ -642,16 +643,17 @@ static void netcp_empty_rx_queue(struct netcp_intf *netcp)
if (unlikely(!desc)) {
dev_err(netcp->ndev_dev, "%s: failed to unmap Rx desc\n",
__func__);
- netcp->ndev->stats.rx_errors++;
+ rx_stats->rx_errors++;
continue;
}
netcp_free_rx_desc_chain(netcp, desc);
- netcp->ndev->stats.rx_dropped++;
+ rx_stats->rx_dropped++;
}
}
static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
{
+ struct netcp_stats *rx_stats = &netcp->stats;
unsigned int dma_sz, buf_len, org_buf_len;
struct knav_dma_desc *desc, *ndesc;
unsigned int pkt_sz = 0, accum_sz;
@@ -757,8 +759,8 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
if (unlikely(ret)) {
dev_err(netcp->ndev_dev, "RX hook %d failed: %d\n",
rx_hook->order, ret);
- netcp->ndev->stats.rx_errors++;
/* Free the primary descriptor */
+ rx_stats->rx_dropped++;
knav_pool_desc_put(netcp->rx_pool, desc);
dev_kfree_skb(skb);
return 0;
@@ -767,8 +769,10 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
/* Free the primary descriptor */
knav_pool_desc_put(netcp->rx_pool, desc);
- netcp->ndev->stats.rx_packets++;
- netcp->ndev->stats.rx_bytes += skb->len;
+ u64_stats_update_begin(&rx_stats->syncp_rx);
+ rx_stats->rx_packets++;
+ rx_stats->rx_bytes += skb->len;
+ u64_stats_update_end(&rx_stats->syncp_rx);
/* push skb up the stack */
skb->protocol = eth_type_trans(skb, netcp->ndev);
@@ -777,7 +781,7 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
free_desc:
netcp_free_rx_desc_chain(netcp, desc);
- netcp->ndev->stats.rx_errors++;
+ rx_stats->rx_errors++;
return 0;
}
@@ -1008,6 +1012,7 @@ static void netcp_free_tx_desc_chain(struct netcp_intf *netcp,
static int netcp_process_tx_compl_packets(struct netcp_intf *netcp,
unsigned int budget)
{
+ struct netcp_stats *tx_stats = &netcp->stats;
struct knav_dma_desc *desc;
struct netcp_tx_cb *tx_cb;
struct sk_buff *skb;
@@ -1022,7 +1027,7 @@ static int netcp_process_tx_compl_packets(struct netcp_intf *netcp,
desc = knav_pool_desc_unmap(netcp->tx_pool, dma, dma_sz);
if (unlikely(!desc)) {
dev_err(netcp->ndev_dev, "failed to unmap Tx desc\n");
- netcp->ndev->stats.tx_errors++;
+ tx_stats->tx_errors++;
continue;
}
@@ -1033,7 +1038,7 @@ static int netcp_process_tx_compl_packets(struct netcp_intf *netcp,
netcp_free_tx_desc_chain(netcp, desc, dma_sz);
if (!skb) {
dev_err(netcp->ndev_dev, "No skb in Tx desc\n");
- netcp->ndev->stats.tx_errors++;
+ tx_stats->tx_errors++;
continue;
}
@@ -1050,8 +1055,10 @@ static int netcp_process_tx_compl_packets(struct netcp_intf *netcp,
netif_wake_subqueue(netcp->ndev, subqueue);
}
- netcp->ndev->stats.tx_packets++;
- netcp->ndev->stats.tx_bytes += skb->len;
+ u64_stats_update_begin(&tx_stats->syncp_tx);
+ tx_stats->tx_packets++;
+ tx_stats->tx_bytes += skb->len;
+ u64_stats_update_end(&tx_stats->syncp_tx);
dev_kfree_skb(skb);
pkts++;
}
@@ -1272,6 +1279,7 @@ static int netcp_tx_submit_skb(struct netcp_intf *netcp,
static int netcp_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct netcp_intf *netcp = netdev_priv(ndev);
+ struct netcp_stats *tx_stats = &netcp->stats;
int subqueue = skb_get_queue_mapping(skb);
struct knav_dma_desc *desc;
int desc_count, ret = 0;
@@ -1287,7 +1295,7 @@ static int netcp_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev)
/* If we get here, the skb has already been dropped */
dev_warn(netcp->ndev_dev, "padding failed (%d), packet dropped\n",
ret);
- ndev->stats.tx_dropped++;
+ tx_stats->tx_dropped++;
return ret;
}
skb->len = NETCP_MIN_PACKET_SIZE;
@@ -1315,7 +1323,7 @@ static int netcp_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev)
return NETDEV_TX_OK;
drop:
- ndev->stats.tx_dropped++;
+ tx_stats->tx_dropped++;
if (desc)
netcp_free_tx_desc_chain(netcp, desc, sizeof(*desc));
dev_kfree_skb(skb);
@@ -1897,12 +1905,46 @@ static int netcp_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
return 0;
}
+static struct rtnl_link_stats64 *
+netcp_get_stats(struct net_device *ndev, struct rtnl_link_stats64 *stats)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ struct netcp_stats *p = &netcp->stats;
+ u64 rxpackets, rxbytes, txpackets, txbytes;
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin_irq(&p->syncp_rx);
+ rxpackets = p->rx_packets;
+ rxbytes = p->rx_bytes;
+ } while (u64_stats_fetch_retry_irq(&p->syncp_rx, start));
+
+ do {
+ start = u64_stats_fetch_begin_irq(&p->syncp_tx);
+ txpackets = p->tx_packets;
+ txbytes = p->tx_bytes;
+ } while (u64_stats_fetch_retry_irq(&p->syncp_tx, start));
+
+ stats->rx_packets = rxpackets;
+ stats->rx_bytes = rxbytes;
+ stats->tx_packets = txpackets;
+ stats->tx_bytes = txbytes;
+
+ /* The following are stored as 32 bit */
+ stats->rx_errors = p->rx_errors;
+ stats->rx_dropped = p->rx_dropped;
+ stats->tx_dropped = p->tx_dropped;
+
+ return stats;
+}
+
static const struct net_device_ops netcp_netdev_ops = {
.ndo_open = netcp_ndo_open,
.ndo_stop = netcp_ndo_stop,
.ndo_start_xmit = netcp_ndo_start_xmit,
.ndo_set_rx_mode = netcp_set_rx_mode,
.ndo_do_ioctl = netcp_ndo_ioctl,
+ .ndo_get_stats64 = netcp_get_stats,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
.ndo_vlan_rx_add_vid = netcp_rx_add_vid,
@@ -1949,6 +1991,8 @@ static int netcp_create_interface(struct netcp_device *netcp_device,
INIT_LIST_HEAD(&netcp->txhook_list_head);
INIT_LIST_HEAD(&netcp->rxhook_list_head);
INIT_LIST_HEAD(&netcp->addr_list);
+ u64_stats_init(&netcp->stats.syncp_rx);
+ u64_stats_init(&netcp->stats.syncp_tx);
netcp->netcp_device = netcp_device;
netcp->dev = netcp_device->device;
netcp->ndev = ndev;
--
1.9.1
^ permalink raw reply related
* [net-next v1 7/8] net: netcp: ale: use ale_status to size the ale table
From: Murali Karicheri @ 2017-01-06 20:37 UTC (permalink / raw)
To: davem, arnd, netdev, linux-kernel, mugunthanvnm, linux-omap,
grygorii.strashko
In-Reply-To: <1483735066-14632-1-git-send-email-m-karicheri2@ti.com>
ALE h/w on newer version of NetCP (K2E/L/G) does provide a ALE_STATUS
register for the size of the ALE Table implemented in h/w. Currently
for example we set ALE Table size to 1024 for NetCP ALE on
K2E even though the ALE Status/Documentation shows it has 8192 entries.
So take advantage of this register to read the size of ALE table supported
and use that value in the driver for the newer version of NetCP ALE.
For NetCP lite, ALE Table size is much less (64) and indicated by a size
of zero in ALE_STATUS. So use that as a default for now. While at it,
also fix the ale table size on 10G switch to 2048 per User guide
http://www.ti.com/lit/ug/spruhj5/spruhj5.pdf
Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
---
drivers/net/ethernet/ti/cpsw_ale.c | 31 ++++++++++++++++++++++++++++++-
drivers/net/ethernet/ti/netcp_ethss.c | 4 +---
2 files changed, 31 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index e15db39..62a18d6 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -33,6 +33,7 @@
/* ALE Registers */
#define ALE_IDVER 0x00
+#define ALE_STATUS 0x04
#define ALE_CONTROL 0x08
#define ALE_PRESCALE 0x10
#define ALE_UNKNOWNVLAN 0x18
@@ -58,6 +59,10 @@
#define ALE_UCAST_OUI 2
#define ALE_UCAST_TOUCHED 3
+#define ALE_TABLE_SIZE_MULTIPLIER 1024
+#define ALE_STATUS_SIZE_MASK 0x1f
+#define ALE_TABLE_SIZE_DEFAULT 64
+
static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits)
{
int idx;
@@ -728,7 +733,7 @@ static void cpsw_ale_timer(unsigned long arg)
void cpsw_ale_start(struct cpsw_ale *ale)
{
- u32 rev;
+ u32 rev, ale_entries;
rev = __raw_readl(ale->params.ale_regs + ALE_IDVER);
if (!ale->params.major_ver_mask)
@@ -740,6 +745,30 @@ void cpsw_ale_start(struct cpsw_ale *ale)
ALE_VERSION_MAJOR(rev, ale->params.major_ver_mask),
ALE_VERSION_MINOR(rev));
+ if (!ale->params.ale_entries) {
+ ale_entries =
+ __raw_readl(ale->params.ale_regs + ALE_STATUS) &
+ ALE_STATUS_SIZE_MASK;
+ /* ALE available on newer NetCP switches has introduced
+ * a register, ALE_STATUS, to indicate the size of ALE
+ * table which shows the size as a multiple of 1024 entries.
+ * For these, params.ale_entries will be set to zero. So
+ * read the register and update the value of ale_entries.
+ * ALE table on NetCP lite, is much smaller and is indicated
+ * by a value of zero in ALE_STATUS. So use a default value
+ * of ALE_TABLE_SIZE_DEFAULT for this. Caller is expected
+ * to set the value of ale_entries for all other versions
+ * of ALE.
+ */
+ if (!ale_entries)
+ ale_entries = ALE_TABLE_SIZE_DEFAULT;
+ else
+ ale_entries *= ALE_TABLE_SIZE_MULTIPLIER;
+ ale->params.ale_entries = ale_entries;
+ }
+ dev_info(ale->params.dev,
+ "ALE Table size %ld\n", ale->params.ale_entries);
+
if (ale->params.nu_switch_ale) {
/* Separate registers for unknown vlan configuration.
* Also there are N bits, where N is number of ale
diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c
index e4a1862..f7bb241 100644
--- a/drivers/net/ethernet/ti/netcp_ethss.c
+++ b/drivers/net/ethernet/ti/netcp_ethss.c
@@ -81,7 +81,6 @@
#define GBENU_CPTS_OFFSET 0x1d000
#define GBENU_ALE_OFFSET 0x1e000
#define GBENU_HOST_PORT_NUM 0
-#define GBENU_NUM_ALE_ENTRIES 1024
#define GBENU_SGMII_MODULE_SIZE 0x100
/* 10G Ethernet SS defines */
@@ -103,7 +102,7 @@
#define XGBE10_ALE_OFFSET 0x700
#define XGBE10_HW_STATS_OFFSET 0x800
#define XGBE10_HOST_PORT_NUM 0
-#define XGBE10_NUM_ALE_ENTRIES 1024
+#define XGBE10_NUM_ALE_ENTRIES 2048
#define GBE_TIMER_INTERVAL (HZ / 2)
@@ -3441,7 +3440,6 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev,
gbe_dev->ale_reg = gbe_dev->switch_regs + GBENU_ALE_OFFSET;
gbe_dev->ale_ports = gbe_dev->max_num_ports;
gbe_dev->host_port = GBENU_HOST_PORT_NUM;
- gbe_dev->ale_entries = GBE13_NUM_ALE_ENTRIES;
gbe_dev->stats_en_mask = (1 << (gbe_dev->max_num_ports)) - 1;
/* Subsystem registers */
--
1.9.1
^ permalink raw reply related
* [net-next v1 5/8] net: netcp: use hw capability to remove FCS word from rx packets
From: Murali Karicheri @ 2017-01-06 20:37 UTC (permalink / raw)
To: davem, arnd, netdev, linux-kernel, mugunthanvnm, linux-omap,
grygorii.strashko
In-Reply-To: <1483735066-14632-1-git-send-email-m-karicheri2@ti.com>
Some of the newer Ethernet switch hw (such as that on k2e/l/g) can
strip the Etherenet FCS from packet at the port 0 egress of the switch.
So use this capability instead of doing it in software.
Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
---
drivers/net/ethernet/ti/netcp.h | 2 ++
drivers/net/ethernet/ti/netcp_core.c | 8 ++++++--
drivers/net/ethernet/ti/netcp_ethss.c | 10 ++++++++--
3 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/ti/netcp.h b/drivers/net/ethernet/ti/netcp.h
index d243c5d..8900a6f 100644
--- a/drivers/net/ethernet/ti/netcp.h
+++ b/drivers/net/ethernet/ti/netcp.h
@@ -102,6 +102,8 @@ struct netcp_intf {
void *rx_fdq[KNAV_DMA_FDQ_PER_CHAN];
struct napi_struct rx_napi;
struct napi_struct tx_napi;
+#define ETH_SW_CAN_REMOVE_ETH_FCS BIT(0)
+ u32 hw_cap;
/* 64-bit netcp stats */
struct netcp_stats stats;
diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c
index b077ed4..68a75cc 100644
--- a/drivers/net/ethernet/ti/netcp_core.c
+++ b/drivers/net/ethernet/ti/netcp_core.c
@@ -739,8 +739,12 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
dev_dbg(netcp->ndev_dev, "mismatch in packet size(%d) & sum of fragments(%d)\n",
pkt_sz, accum_sz);
- /* Remove ethernet FCS from the packet */
- __pskb_trim(skb, skb->len - ETH_FCS_LEN);
+ /* Newer version of the Ethernet switch can trim the Ethernet FCS
+ * from the packet and is indicated in hw_cap. So trim it only for
+ * older h/w
+ */
+ if (!(netcp->hw_cap & ETH_SW_CAN_REMOVE_ETH_FCS))
+ __pskb_trim(skb, skb->len - ETH_FCS_LEN);
/* Call each of the RX hooks */
p_info.skb = skb;
diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c
index 4a64b3e..6bb8e26 100644
--- a/drivers/net/ethernet/ti/netcp_ethss.c
+++ b/drivers/net/ethernet/ti/netcp_ethss.c
@@ -122,6 +122,7 @@
#define MACSL_FULLDUPLEX BIT(0)
#define GBE_CTL_P0_ENABLE BIT(2)
+#define ETH_SW_CTL_P0_TX_CRC_REMOVE BIT(13)
#define GBE13_REG_VAL_STAT_ENABLE_ALL 0xff
#define XGBE_REG_VAL_STAT_ENABLE_ALL 0xf
#define GBE_STATS_CD_SEL BIT(28)
@@ -2821,7 +2822,7 @@ static int gbe_open(void *intf_priv, struct net_device *ndev)
struct netcp_intf *netcp = netdev_priv(ndev);
struct gbe_slave *slave = gbe_intf->slave;
int port_num = slave->port_num;
- u32 reg;
+ u32 reg, val;
int ret;
reg = readl(GBE_REG_ADDR(gbe_dev, switch_regs, id_ver));
@@ -2851,7 +2852,12 @@ static int gbe_open(void *intf_priv, struct net_device *ndev)
writel(0, GBE_REG_ADDR(gbe_dev, switch_regs, ptype));
/* Control register */
- writel(GBE_CTL_P0_ENABLE, GBE_REG_ADDR(gbe_dev, switch_regs, control));
+ val = GBE_CTL_P0_ENABLE;
+ if (IS_SS_ID_MU(gbe_dev)) {
+ val |= ETH_SW_CTL_P0_TX_CRC_REMOVE;
+ netcp->hw_cap = ETH_SW_CAN_REMOVE_ETH_FCS;
+ }
+ writel(val, GBE_REG_ADDR(gbe_dev, switch_regs, control));
/* All statistics enabled and STAT AB visible by default */
writel(gbe_dev->stats_en_mask, GBE_REG_ADDR(gbe_dev, switch_regs,
--
1.9.1
^ permalink raw reply related
* [net-next v1 6/8] net: netcp: ale: update to support unknown vlan controls for NU switch
From: Murali Karicheri @ 2017-01-06 20:37 UTC (permalink / raw)
To: davem, arnd, netdev, linux-kernel, mugunthanvnm, linux-omap,
grygorii.strashko
In-Reply-To: <1483735066-14632-1-git-send-email-m-karicheri2@ti.com>
In NU Ethernet switch used on some of the Keystone SoCs, there is
separate UNKNOWNVLAN register for membership, unreg mcast flood, reg
mcast flood and force untag egress bits in ALE. So control for these
fields require different address offset, shift and size of field.
As this ALE has the same version number as ALE in CPSW found on other
SoCs, customization based on version number is not possible. So
use a configuration parameter, nu_switch_ale, to identify the ALE
ALE found in NU Switch. Different treatment is needed for NU Switch
ALE due to difference in the ale table bits, separate unknown vlan
registers etc. The register information available in ale_controls,
needs to be updated to support the netcp NU switch h/w. So it is not
constant array any more since it needs to be updated based
on ALE type. The header of the file is also updated to indicate it
supports N port switch ALE, not just 3 port. The version mask is
3 bits in NU Switch ALE vs 8 bits on other ALE types.
While at it, change the debug print to info print so that ALE
version gets displayed in boot log.
Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
---
drivers/net/ethernet/ti/cpsw_ale.c | 50 +++++++++++++++++++++++++++++++----
drivers/net/ethernet/ti/cpsw_ale.h | 13 ++++++++-
drivers/net/ethernet/ti/netcp_ethss.c | 5 +++-
3 files changed, 61 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index 43b061b..e15db39 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -1,5 +1,5 @@
/*
- * Texas Instruments 3-Port Ethernet Switch Address Lookup Engine
+ * Texas Instruments N-Port Ethernet Switch Address Lookup Engine
*
* Copyright (C) 2012 Texas Instruments
*
@@ -27,8 +27,9 @@
#define BITMASK(bits) (BIT(bits) - 1)
-#define ALE_VERSION_MAJOR(rev) ((rev >> 8) & 0xff)
+#define ALE_VERSION_MAJOR(rev, mask) (((rev) >> 8) & (mask))
#define ALE_VERSION_MINOR(rev) (rev & 0xff)
+#define ALE_VERSION_1R4 0x0104
/* ALE Registers */
#define ALE_IDVER 0x00
@@ -39,6 +40,12 @@
#define ALE_TABLE 0x34
#define ALE_PORTCTL 0x40
+/* ALE NetCP NU switch specific Registers */
+#define ALE_UNKNOWNVLAN_MEMBER 0x90
+#define ALE_UNKNOWNVLAN_UNREG_MCAST_FLOOD 0x94
+#define ALE_UNKNOWNVLAN_REG_MCAST_FLOOD 0x98
+#define ALE_UNKNOWNVLAN_FORCE_UNTAG_EGRESS 0x9C
+
#define ALE_TABLE_WRITE BIT(31)
#define ALE_TYPE_FREE 0
@@ -464,7 +471,7 @@ struct ale_control_info {
int bits;
};
-static const struct ale_control_info ale_controls[ALE_NUM_CONTROLS] = {
+static struct ale_control_info ale_controls[ALE_NUM_CONTROLS] = {
[ALE_ENABLE] = {
.name = "enable",
.offset = ALE_CONTROL,
@@ -724,8 +731,41 @@ void cpsw_ale_start(struct cpsw_ale *ale)
u32 rev;
rev = __raw_readl(ale->params.ale_regs + ALE_IDVER);
- dev_dbg(ale->params.dev, "initialized cpsw ale revision %d.%d\n",
- ALE_VERSION_MAJOR(rev), ALE_VERSION_MINOR(rev));
+ if (!ale->params.major_ver_mask)
+ ale->params.major_ver_mask = 0xff;
+ ale->version =
+ (ALE_VERSION_MAJOR(rev, ale->params.major_ver_mask) << 8) |
+ ALE_VERSION_MINOR(rev);
+ dev_info(ale->params.dev, "initialized cpsw ale version %d.%d\n",
+ ALE_VERSION_MAJOR(rev, ale->params.major_ver_mask),
+ ALE_VERSION_MINOR(rev));
+
+ if (ale->params.nu_switch_ale) {
+ /* Separate registers for unknown vlan configuration.
+ * Also there are N bits, where N is number of ale
+ * ports and shift value should be 0
+ */
+ ale_controls[ALE_PORT_UNKNOWN_VLAN_MEMBER].bits =
+ ale->params.ale_ports;
+ ale_controls[ALE_PORT_UNKNOWN_VLAN_MEMBER].offset =
+ ALE_UNKNOWNVLAN_MEMBER;
+ ale_controls[ALE_PORT_UNKNOWN_MCAST_FLOOD].bits =
+ ale->params.ale_ports;
+ ale_controls[ALE_PORT_UNKNOWN_MCAST_FLOOD].shift = 0;
+ ale_controls[ALE_PORT_UNKNOWN_MCAST_FLOOD].offset =
+ ALE_UNKNOWNVLAN_UNREG_MCAST_FLOOD;
+ ale_controls[ALE_PORT_UNKNOWN_REG_MCAST_FLOOD].bits =
+ ale->params.ale_ports;
+ ale_controls[ALE_PORT_UNKNOWN_REG_MCAST_FLOOD].shift = 0;
+ ale_controls[ALE_PORT_UNKNOWN_REG_MCAST_FLOOD].offset =
+ ALE_UNKNOWNVLAN_REG_MCAST_FLOOD;
+ ale_controls[ALE_PORT_UNTAGGED_EGRESS].bits =
+ ale->params.ale_ports;
+ ale_controls[ALE_PORT_UNTAGGED_EGRESS].shift = 0;
+ ale_controls[ALE_PORT_UNTAGGED_EGRESS].offset =
+ ALE_UNKNOWNVLAN_FORCE_UNTAG_EGRESS;
+ }
+
cpsw_ale_control_set(ale, 0, ALE_ENABLE, 1);
cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1);
diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h
index a700189..b1c7954 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.h
+++ b/drivers/net/ethernet/ti/cpsw_ale.h
@@ -1,5 +1,5 @@
/*
- * Texas Instruments 3-Port Ethernet Switch Address Lookup Engine APIs
+ * Texas Instruments N-Port Ethernet Switch Address Lookup Engine APIs
*
* Copyright (C) 2012 Texas Instruments
*
@@ -21,6 +21,16 @@ struct cpsw_ale_params {
unsigned long ale_ageout; /* in secs */
unsigned long ale_entries;
unsigned long ale_ports;
+ /* NU Switch has specific handling as number of bits in ALE entries
+ * are different than other versions of ALE. Also there are specific
+ * registers for unknown vlan specific fields. So use nu_switch_ale
+ * to identify this hardware.
+ */
+ bool nu_switch_ale;
+ /* mask bit used in NU Switch ALE is 3 bits instead of 8 bits. So
+ * pass it from caller.
+ */
+ u32 major_ver_mask;
};
struct cpsw_ale {
@@ -28,6 +38,7 @@ struct cpsw_ale {
struct timer_list timer;
unsigned long ageout;
int allmulti;
+ u32 version;
};
enum cpsw_ale_control {
diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c
index 6bb8e26..e4a1862 100644
--- a/drivers/net/ethernet/ti/netcp_ethss.c
+++ b/drivers/net/ethernet/ti/netcp_ethss.c
@@ -3609,7 +3609,10 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
ale_params.ale_ageout = GBE_DEFAULT_ALE_AGEOUT;
ale_params.ale_entries = gbe_dev->ale_entries;
ale_params.ale_ports = gbe_dev->ale_ports;
-
+ if (IS_SS_ID_MU(gbe_dev)) {
+ ale_params.major_ver_mask = 0x7;
+ ale_params.nu_switch_ale = true;
+ }
gbe_dev->ale = cpsw_ale_create(&ale_params);
if (!gbe_dev->ale) {
dev_err(gbe_dev->dev, "error initializing ale engine\n");
--
1.9.1
^ permalink raw reply related
* Re: [RFC PATCH next] ipv6: do not send RTM_DELADDR for tentative addresses
From: David Miller @ 2017-01-06 20:39 UTC (permalink / raw)
To: mahesh; +Cc: netdev, maheshb, yoshfuji, kaber, hannes
In-Reply-To: <20170104230101.17470-1-mahesh@bandewar.net>
From: Mahesh Bandewar <mahesh@bandewar.net>
Date: Wed, 4 Jan 2017 15:01:01 -0800
> From: Mahesh Bandewar <maheshb@google.com>
>
> RTM_NEWADDR notification is sent when IFA_F_TENTATIVE is cleared from
> the address. So if the address is added and deleted before DAD probes
> completes, the RTM_DELADDR will be sent for which there was no
> RTM_NEWADDR causing asymmetry in notification. However if the same
> logic is used while sending RTM_DELADDR notification, this asymmetry
> can be avoided.
>
> Signed-off-by: Mahesh Bandewar <maheshb@google.com>
This makes a lot of sense, applied, thanks!
^ permalink raw reply
* Re: [PATCH net-next 1/4] siphash: add cryptographically secure PRF
From: David Miller @ 2017-01-06 20:41 UTC (permalink / raw)
To: jeanphilippe.aumasson
Cc: Jason, netdev, linux-kernel, torvalds, ebiggers3, David.Laight,
eric.dumazet
In-Reply-To: <CAGiyFdczUy_jHr6qvz_V=9zZ2b59N-2ogL3j4Qk2qwSYuFJw4g@mail.gmail.com>
Please do not quote an entire large patch, just to make a small comment or
annotation. This makes it so that every reader of your posting has to
scroll down a lot just to see a small amount of new content.
Simply edit down the quoted material to the actually required context, and
then add the content you wish.
I do realize that a lot of email clients make this difficult, but that is
no excuse for not maintaining this basic level of consideration for the
other people on this mailing list.
Thanks.
^ permalink raw reply
* Re: [PATCH net-next] liquidio: fix wrong information about channels reported to ethtool
From: David Miller @ 2017-01-06 20:44 UTC (permalink / raw)
To: felix.manlunas; +Cc: netdev, raghu.vatsavayi, derek.chickles, satananda.burla
In-Reply-To: <20170105001850.GA20747@felix.cavium.com>
From: Felix Manlunas <felix.manlunas@cavium.com>
Date: Wed, 4 Jan 2017 16:18:50 -0800
> From: Weilin Chang <weilin.chang@cavium.com>
>
> Information reported to ethtool about channels is sometimes wrong for PF,
> and always wrong for VF. Fix them by getting the information from the
> right fields from the right structs.
>
> Signed-off-by: Weilin Chang <weilin.chang@cavium.com>
> Signed-off-by: Felix Manlunas <felix.manlunas@cavium.com>
> Signed-off-by: Derek Chickles <derek.chickles@cavium.com>
> Signed-off-by: Satanand Burla <satananda.burla@cavium.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next] net: dsa: remove version string
From: David Miller @ 2017-01-06 20:49 UTC (permalink / raw)
To: vivien.didelot; +Cc: netdev, linux-kernel, kernel, f.fainelli, andrew
In-Reply-To: <20170105172841.16221-1-vivien.didelot@savoirfairelinux.com>
From: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Date: Thu, 5 Jan 2017 12:28:41 -0500
> The dsa_driver_version string is irrelevant and has not been bumped
> since its introduction about 9 years ago. Kill it.
>
> Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH v2 4/7] x86: put msr-index.h in uapi
From: Andy Shevchenko @ 2017-01-06 20:50 UTC (permalink / raw)
To: Nicolas Dichtel
Cc: Arnd Bergmann, mmarek, linux-kbuild, Linux Documentation List,
linux-kernel@vger.kernel.org, linux-alpha, linux-snps-arc,
linux-arm Mailing List, adi-buildroot-devel, linux-c6x-dev, Cris,
uclinux-h8-devel, linux-hexagon, linux-ia64, linux-m68k,
linux-metag, linux-mips, linux-am33-list, nios2-dev, openrisc,
linux-parisc, "open list:LINUX FOR POWERPC PA SEMI PWRFICI
In-Reply-To: <1483695839-18660-5-git-send-email-nicolas.dichtel@6wind.com>
On Fri, Jan 6, 2017 at 11:43 AM, Nicolas Dichtel
<nicolas.dichtel@6wind.com> wrote:
> This header file is exported, thus move it to uapi.
Just hint for the future:
-M (move)
-C (copy)
-D (delete) [though this is NOT for applying]
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH net-next v2] net: dsa: b53: Utilize common helpers for u64/MAC
From: David Miller @ 2017-01-06 20:51 UTC (permalink / raw)
To: f.fainelli; +Cc: netdev, andrew, vivien.didelot, volodymyr.bendiuga
In-Reply-To: <20170105190858.12623-1-f.fainelli@gmail.com>
From: Florian Fainelli <f.fainelli@gmail.com>
Date: Thu, 5 Jan 2017 11:08:58 -0800
> Utilize the two functions recently introduced: u64_to_ether() and
> ether_to_u64() instead of our own versions.
>
> Reviewed-by: Andrew Lunn <andrew@lunn.ch>
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Applied.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox