All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/2] crypto: Implement a generic crypto statistics
@ 2018-09-19 10:10 Corentin Labbe
  2018-09-19 10:10 ` [PATCH v3 1/2] " Corentin Labbe
                   ` (2 more replies)
  0 siblings, 3 replies; 18+ messages in thread
From: Corentin Labbe @ 2018-09-19 10:10 UTC (permalink / raw)
  To: davem, herbert, nhorman; +Cc: linux-crypto, linux-kernel, Corentin Labbe

This patch is a try to implement a generic crypto driver statistics.
The goal is to have an "ifconfig" for crypto device.

Some driver tried to implement this via a debugfs interface.

This serie do it directly in the crypto API and give access to stats
via the crypto_user(netlink) API.
Then an userspace tool will collect information via netlink.
Note that this userspace tool is heavily copied from libkcapi and if
Stephan Mueller agree, I will made a PR for adding getstat to it unless
tools/crypto is the good place for it.

Example of output:
pkcs1pad(rsa-sun8i-ce,sha1)     Akcipher
        Encrypt: 0 bytes: 0
        Decrypt: 0 bytes: 0
        Sign: 0
        Verify: 5
        Errors: 0
cryptd(__xts-aes-ce)    cipher
        Encrypt: 0 bytes: 0
        Decrypt: 0 bytes: 0
        Errors: 0
xts-aes-ce      cipher
        Encrypt: 17 bytes: 4384
        Decrypt: 17 bytes: 4384
        Errors: 0
cryptd(__ctr-aes-ce)    cipher
        Encrypt: 0 bytes: 0
        Decrypt: 0 bytes: 0
        Errors: 0
ctr-aes-ce      cipher
        Encrypt: 19 bytes: 5551
        Decrypt: 19 bytes: 5551
        Errors: 0
cryptd(__cbc-aes-ce)    cipher
        Encrypt: 0 bytes: 0
        Decrypt: 0 bytes: 0
        Errors: 0
cbc-aes-ce      cipher
        Encrypt: 19 bytes: 3040
        Decrypt: 19 bytes: 3040
        Errors: 0
cryptd(__ecb-aes-ce)    cipher
        Encrypt: 0 bytes: 0
        Decrypt: 0 bytes: 0
        Errors: 0
ecb-aes-ce      cipher
        Encrypt: 14 bytes: 2624
        Decrypt: 14 bytes: 2624
        Errors: 0
cbcmac-aes-ce   Hash
        Hash: 20 bytes: 1244
        Errors: 0
xcbc-aes-ce     Hash
        Hash: 28 bytes: 543
        Errors: 0
cmac-aes-ce     Hash
        Hash: 36 bytes: 1472
        Errors: 0
__xts-aes-ce    cipher
        Encrypt: 17 bytes: 4384
        Decrypt: 17 bytes: 4384
        Errors: 0
ctr-aes-ce      cipher
        Encrypt: 19 bytes: 5551
        Decrypt: 19 bytes: 5551
        Errors: 0
__ctr-aes-ce    cipher
        Encrypt: 19 bytes: 5551
        Decrypt: 19 bytes: 5551
        Errors: 0
__cbc-aes-ce    cipher
        Encrypt: 19 bytes: 3040
        Decrypt: 19 bytes: 3040
        Errors: 0
__ecb-aes-ce    cipher
        Encrypt: 14 bytes: 2624
        Decrypt: 14 bytes: 2624
        Errors: 0
rsa-sun8i-ce    Akcipher
        Encrypt: 7 bytes: 232
        Decrypt: 6 bytes: 1152
        Sign: 0
        Verify: 5
        Errors: 0
sun8i_ce_rng    RNG
        Seed: 0
        Generate: 0 bytes: 0
        Errors: 0
ecb(des3_ede-generic)   cipher
        Encrypt: 24 bytes: 4584
        Decrypt: 24 bytes: 4584
        Errors: 0
ecb-des3-sun8i-ce       cipher
        Encrypt: 18 bytes: 3072
        Decrypt: 18 bytes: 3072
        Errors: 0
cbc(des3_ede-generic)   cipher
        Encrypt: 14 bytes: 5104
        Decrypt: 14 bytes: 5104
        Errors: 0
aes-ce  cipher
        Encrypt: 0 bytes: 0
        Decrypt: 0 bytes: 0
        Errors: 0
des3_ede-generic        cipher
        Encrypt: 0 bytes: 0
        Decrypt: 0 bytes: 0
        Errors: 0
des-generic     cipher
        Encrypt: 0 bytes: 0
        Decrypt: 0 bytes: 0
        Errors: 0
aes-arm64       cipher
        Encrypt: 0 bytes: 0
        Decrypt: 0 bytes: 0
        Errors: 0
crc32c-arm64-ce Hash
        Hash: 92 bytes: 20649
        Errors: 0
cbc-des3-sun8i-ce       cipher
        Encrypt: 10 bytes: 3488
        Decrypt: 10 bytes: 3488
        Errors: 0
crc32-arm64-ce  Hash
        Hash: 92 bytes: 20649
        Errors: 0
ecb-aes-sun8i-ce        cipher
        Encrypt: 18 bytes: 3168
        Decrypt: 18 bytes: 3168
        Errors: 0
cbc-aes-sun8i-ce        cipher
        Encrypt: 24 bytes: 3712
        Decrypt: 24 bytes: 3712
        Errors: 0
sha256-ce       Hash
        Hash: 26 bytes: 8860
        Errors: 0
sha224-ce       Hash
        Hash: 26 bytes: 8860
        Errors: 0
cts(cbc-aes-sun8i-ce)   cipher
        Encrypt: 24 bytes: 956
        Decrypt: 24 bytes: 956
        Errors: 0
sha224-arm64-neon       Hash
        Hash: 26 bytes: 8860
        Errors: 0
sha256-arm64-neon       Hash
        Hash: 26 bytes: 8860
        Errors: 0
sha224-arm64    Hash
        Hash: 26 bytes: 8860
        Errors: 0
sha256-arm64    Hash
        Hash: 26 bytes: 8860
        Errors: 0
ctr-aes-sun8i-ce        cipher
        Encrypt: 24 bytes: 6738
        Decrypt: 24 bytes: 6738
        Errors: 0
sha1-ce Hash
        Hash: 28 bytes: 9191
        Errors: 0
ecdh-generic    KPP
        Setsecret: 4
        Generate public key: 3
        Compute_shared_secret: 4
        Errors: 0
ghash-generic   Hash
        Hash: 32 bytes: 4358
        Errors: 0
jitterentropy_rng       RNG
        Seed: 0
        Generate: 1 bytes: 48
        Errors: 0
drbg_nopr_hmac_sha256   RNG
       Seed: 5
        Generate: 9 bytes: 1056
        Errors: 0
drbg_nopr_hmac_sha512   RNG
        Seed: 0
        Generate: 0 bytes: 0
        Errors: 0
drbg_nopr_hmac_sha384   RNG
        Seed: 0
        Generate: 0 bytes: 0
        Errors: 0
drbg_nopr_hmac_sha1     RNG
        Seed: 0
        Generate: 0 bytes: 0
        Errors: 0
drbg_pr_hmac_sha256     RNG
        Seed: 4
        Generate: 8 bytes: 1024
        Errors: 0
drbg_pr_hmac_sha512     RNG
        Seed: 0
        Generate: 0 bytes: 0
        Errors: 0
drbg_pr_hmac_sha384     RNG
        Seed: 0
        Generate: 0 bytes: 0
        Errors: 0
drbg_pr_hmac_sha1       RNG
        Seed: 0
        Generate: 0 bytes: 0
        Errors: 0
crct10dif-generic       Hash
        Hash: 24 bytes: 19893
        Errors: 0
crc32c-generic  Hash
        Hash: 92 bytes: 20649
        Errors: 0
aes-generic     cipher
        Encrypt: 0 bytes: 0
        Decrypt: 0 bytes: 0
        Errors: 0
sha224-generic  Hash
        Hash: 26 bytes: 8860
        Errors: 0
sha256-generic  Hash
        Hash: 26 bytes: 8860
        Errors: 0
sha1-generic    Hash
        Hash: 28 bytes: 9191
        Errors: 0
digest_null-generic     Hash
        Hash: 0 bytes: 0
        Errors: 0
compress_null-generic   Compress
        Compress: 0 bytes: 0
        Decompress: 0 bytes: 0
        Errors: 0
ecb-cipher_null cipher
        Encrypt: 0 bytes: 0
        Decrypt: 0 bytes: 0
        Errors: 0
cipher_null-generic     cipher
        Encrypt: 0 bytes: 0
        Decrypt: 0 bytes: 0
        Errors: 0
rsa-generic     Akcipher
        Encrypt: 17 bytes: 2832
        Decrypt: 9 bytes: 1920
        Sign: 0
        Verify: 36
        Errors: 0

Futur possible additions:
- Add a "number of needed fallback" statistics.
- statistics for maximum request size

Please let me know your opinions about it

Regards

Changes since v2:
- added documentation on new struct crypto_alg members.

Changes since v1:
- Do not use anymore CRYPTO_MSG_GETALG and added a dedicated CRYPTO_MSG_GETSTAT

Changes since RFC:
- Use cryptouser(netlink) instead of /sys
- Use atomic_t instead of unsigned long
- moved stat code into dedicated inline function
- spelling fixes

Corentin Labbe (2):
  crypto: Implement a generic crypto statistics
  crypto: tools: Add cryptostat userspace

 crypto/Kconfig                               |  11 +
 crypto/Makefile                              |   1 +
 crypto/ahash.c                               |  21 +-
 crypto/algapi.c                              |   8 +
 crypto/{crypto_user.c => crypto_user_base.c} |   9 +-
 crypto/crypto_user_stat.c                    | 463 +++++++++++++++++++++++++++
 crypto/rng.c                                 |   1 +
 include/crypto/acompress.h                   |  38 ++-
 include/crypto/aead.h                        |  51 ++-
 include/crypto/akcipher.h                    |  76 ++++-
 include/crypto/hash.h                        |  32 +-
 include/crypto/internal/cryptouser.h         |   8 +
 include/crypto/kpp.h                         |  51 ++-
 include/crypto/rng.h                         |  29 +-
 include/crypto/skcipher.h                    |  44 ++-
 include/linux/crypto.h                       | 110 ++++++-
 include/uapi/linux/cryptouser.h              |  52 +++
 tools/crypto/getstat.c                       | 294 +++++++++++++++++
 18 files changed, 1264 insertions(+), 35 deletions(-)
 rename crypto/{crypto_user.c => crypto_user_base.c} (97%)
 create mode 100644 crypto/crypto_user_stat.c
 create mode 100644 include/crypto/internal/cryptouser.h
 create mode 100644 tools/crypto/getstat.c

-- 
2.16.4

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v3 1/2] crypto: Implement a generic crypto statistics
  2018-09-19 10:10 [PATCH v3 0/2] crypto: Implement a generic crypto statistics Corentin Labbe
@ 2018-09-19 10:10 ` Corentin Labbe
  2018-11-03 22:19   ` Eric Biggers
                     ` (2 more replies)
  2018-09-19 10:10 ` [PATCH v3 2/2] crypto: tools: Add cryptostat userspace Corentin Labbe
  2018-09-28  5:08 ` [PATCH v3 0/2] crypto: Implement a generic crypto statistics Herbert Xu
  2 siblings, 3 replies; 18+ messages in thread
From: Corentin Labbe @ 2018-09-19 10:10 UTC (permalink / raw)
  To: davem, herbert, nhorman; +Cc: linux-crypto, linux-kernel, Corentin Labbe

This patch implement a generic way to get statistics about all crypto
usages.

Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
---
 crypto/Kconfig                               |  11 +
 crypto/Makefile                              |   1 +
 crypto/ahash.c                               |  21 +-
 crypto/algapi.c                              |   8 +
 crypto/{crypto_user.c => crypto_user_base.c} |   9 +-
 crypto/crypto_user_stat.c                    | 463 +++++++++++++++++++++++++++
 crypto/rng.c                                 |   1 +
 include/crypto/acompress.h                   |  38 ++-
 include/crypto/aead.h                        |  51 ++-
 include/crypto/akcipher.h                    |  76 ++++-
 include/crypto/hash.h                        |  32 +-
 include/crypto/internal/cryptouser.h         |   8 +
 include/crypto/kpp.h                         |  51 ++-
 include/crypto/rng.h                         |  29 +-
 include/crypto/skcipher.h                    |  44 ++-
 include/linux/crypto.h                       | 110 ++++++-
 include/uapi/linux/cryptouser.h              |  52 +++
 17 files changed, 970 insertions(+), 35 deletions(-)
 rename crypto/{crypto_user.c => crypto_user_base.c} (97%)
 create mode 100644 crypto/crypto_user_stat.c
 create mode 100644 include/crypto/internal/cryptouser.h

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 90f2811fac5f..4ef95b0b25a3 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -1799,6 +1799,17 @@ config CRYPTO_USER_API_AEAD
 	  This option enables the user-spaces interface for AEAD
 	  cipher algorithms.
 
+config CRYPTO_STATS
+	bool "Crypto usage statistics for User-space"
+	help
+	  This option enables the gathering of crypto stats.
+	  This will collect:
+	  - encrypt/decrypt size and numbers of symmeric operations
+	  - compress/decompress size and numbers of compress operations
+	  - size and numbers of hash operations
+	  - encrypt/decrypt/sign/verify numbers for asymmetric operations
+	  - generate/seed numbers for rng operations
+
 config CRYPTO_HASH_INFO
 	bool
 
diff --git a/crypto/Makefile b/crypto/Makefile
index d719843f8b6e..ff5c2bbda04a 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -54,6 +54,7 @@ cryptomgr-y := algboss.o testmgr.o
 
 obj-$(CONFIG_CRYPTO_MANAGER2) += cryptomgr.o
 obj-$(CONFIG_CRYPTO_USER) += crypto_user.o
+crypto_user-y := crypto_user_base.o crypto_user_stat.o
 obj-$(CONFIG_CRYPTO_CMAC) += cmac.o
 obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
 obj-$(CONFIG_CRYPTO_VMAC) += vmac.o
diff --git a/crypto/ahash.c b/crypto/ahash.c
index 78aaf2158c43..e21667b4e10a 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -364,24 +364,35 @@ static int crypto_ahash_op(struct ahash_request *req,
 
 int crypto_ahash_final(struct ahash_request *req)
 {
-	return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->final);
+	int ret;
+
+	ret = crypto_ahash_op(req, crypto_ahash_reqtfm(req)->final);
+	crypto_stat_ahash_final(req, ret);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(crypto_ahash_final);
 
 int crypto_ahash_finup(struct ahash_request *req)
 {
-	return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->finup);
+	int ret;
+
+	ret = crypto_ahash_op(req, crypto_ahash_reqtfm(req)->finup);
+	crypto_stat_ahash_final(req, ret);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(crypto_ahash_finup);
 
 int crypto_ahash_digest(struct ahash_request *req)
 {
 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	int ret;
 
 	if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
-		return -ENOKEY;
-
-	return crypto_ahash_op(req, tfm->digest);
+		ret = -ENOKEY;
+	else
+		ret = crypto_ahash_op(req, tfm->digest);
+	crypto_stat_ahash_final(req, ret);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(crypto_ahash_digest);
 
diff --git a/crypto/algapi.c b/crypto/algapi.c
index 38daa8677da9..2545c5f89c4c 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -258,6 +258,14 @@ static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg)
 	list_add(&alg->cra_list, &crypto_alg_list);
 	list_add(&larval->alg.cra_list, &crypto_alg_list);
 
+	atomic_set(&alg->encrypt_cnt, 0);
+	atomic_set(&alg->decrypt_cnt, 0);
+	atomic64_set(&alg->encrypt_tlen, 0);
+	atomic64_set(&alg->decrypt_tlen, 0);
+	atomic_set(&alg->verify_cnt, 0);
+	atomic_set(&alg->cipher_err_cnt, 0);
+	atomic_set(&alg->sign_cnt, 0);
+
 out:
 	return larval;
 
diff --git a/crypto/crypto_user.c b/crypto/crypto_user_base.c
similarity index 97%
rename from crypto/crypto_user.c
rename to crypto/crypto_user_base.c
index 0e89b5457cab..e41f6cc33fff 100644
--- a/crypto/crypto_user.c
+++ b/crypto/crypto_user_base.c
@@ -29,6 +29,7 @@
 #include <crypto/internal/rng.h>
 #include <crypto/akcipher.h>
 #include <crypto/kpp.h>
+#include <crypto/internal/cryptouser.h>
 
 #include "internal.h"
 
@@ -37,7 +38,7 @@
 static DEFINE_MUTEX(crypto_cfg_mutex);
 
 /* The crypto netlink socket */
-static struct sock *crypto_nlsk;
+struct sock *crypto_nlsk;
 
 struct crypto_dump_info {
 	struct sk_buff *in_skb;
@@ -46,7 +47,7 @@ struct crypto_dump_info {
 	u16 nlmsg_flags;
 };
 
-static struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact)
+struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact)
 {
 	struct crypto_alg *q, *alg = NULL;
 
@@ -461,6 +462,7 @@ static const int crypto_msg_min[CRYPTO_NR_MSGTYPES] = {
 	[CRYPTO_MSG_UPDATEALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
 	[CRYPTO_MSG_GETALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
 	[CRYPTO_MSG_DELRNG	- CRYPTO_MSG_BASE] = 0,
+	[CRYPTO_MSG_GETSTAT	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
 };
 
 static const struct nla_policy crypto_policy[CRYPTOCFGA_MAX+1] = {
@@ -481,6 +483,9 @@ static const struct crypto_link {
 						       .dump = crypto_dump_report,
 						       .done = crypto_dump_report_done},
 	[CRYPTO_MSG_DELRNG	- CRYPTO_MSG_BASE] = { .doit = crypto_del_rng },
+	[CRYPTO_MSG_GETSTAT	- CRYPTO_MSG_BASE] = { .doit = crypto_reportstat,
+						       .dump = crypto_dump_reportstat,
+						       .done = crypto_dump_reportstat_done},
 };
 
 static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
diff --git a/crypto/crypto_user_stat.c b/crypto/crypto_user_stat.c
new file mode 100644
index 000000000000..46ad3bae17bc
--- /dev/null
+++ b/crypto/crypto_user_stat.c
@@ -0,0 +1,463 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Crypto user configuration API.
+ *
+ * Copyright (C) 2017-2018 Corentin Labbe <clabbe@baylibre.com>
+ *
+ */
+
+#include <linux/crypto.h>
+#include <linux/cryptouser.h>
+#include <linux/sched.h>
+#include <net/netlink.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/internal/rng.h>
+#include <crypto/akcipher.h>
+#include <crypto/kpp.h>
+#include <crypto/internal/cryptouser.h>
+
+#include "internal.h"
+
+#define null_terminated(x)	(strnlen(x, sizeof(x)) < sizeof(x))
+
+static DEFINE_MUTEX(crypto_cfg_mutex);
+
+extern struct sock *crypto_nlsk;
+
+struct crypto_dump_info {
+	struct sk_buff *in_skb;
+	struct sk_buff *out_skb;
+	u32 nlmsg_seq;
+	u16 nlmsg_flags;
+};
+
+static int crypto_report_aead(struct sk_buff *skb, struct crypto_alg *alg)
+{
+	struct crypto_stat raead;
+	u64 v64;
+	u32 v32;
+
+	strncpy(raead.type, "aead", sizeof(raead.type));
+
+	v32 = atomic_read(&alg->encrypt_cnt);
+	raead.stat_encrypt_cnt = v32;
+	v64 = atomic64_read(&alg->encrypt_tlen);
+	raead.stat_encrypt_tlen = v64;
+	v32 = atomic_read(&alg->decrypt_cnt);
+	raead.stat_decrypt_cnt = v32;
+	v64 = atomic64_read(&alg->decrypt_tlen);
+	raead.stat_decrypt_tlen = v64;
+	v32 = atomic_read(&alg->aead_err_cnt);
+	raead.stat_aead_err_cnt = v32;
+
+	if (nla_put(skb, CRYPTOCFGA_STAT_AEAD,
+		    sizeof(struct crypto_stat), &raead))
+		goto nla_put_failure;
+	return 0;
+
+nla_put_failure:
+	return -EMSGSIZE;
+}
+
+static int crypto_report_cipher(struct sk_buff *skb, struct crypto_alg *alg)
+{
+	struct crypto_stat rcipher;
+	u64 v64;
+	u32 v32;
+
+	strlcpy(rcipher.type, "cipher", sizeof(rcipher.type));
+
+	v32 = atomic_read(&alg->encrypt_cnt);
+	rcipher.stat_encrypt_cnt = v32;
+	v64 = atomic64_read(&alg->encrypt_tlen);
+	rcipher.stat_encrypt_tlen = v64;
+	v32 = atomic_read(&alg->decrypt_cnt);
+	rcipher.stat_decrypt_cnt = v32;
+	v64 = atomic64_read(&alg->decrypt_tlen);
+	rcipher.stat_decrypt_tlen = v64;
+	v32 = atomic_read(&alg->cipher_err_cnt);
+	rcipher.stat_cipher_err_cnt = v32;
+
+	if (nla_put(skb, CRYPTOCFGA_STAT_CIPHER,
+		    sizeof(struct crypto_stat), &rcipher))
+		goto nla_put_failure;
+	return 0;
+
+nla_put_failure:
+	return -EMSGSIZE;
+}
+
+static int crypto_report_comp(struct sk_buff *skb, struct crypto_alg *alg)
+{
+	struct crypto_stat rcomp;
+	u64 v64;
+	u32 v32;
+
+	strlcpy(rcomp.type, "compression", sizeof(rcomp.type));
+	v32 = atomic_read(&alg->compress_cnt);
+	rcomp.stat_compress_cnt = v32;
+	v64 = atomic64_read(&alg->compress_tlen);
+	rcomp.stat_compress_tlen = v64;
+	v32 = atomic_read(&alg->decompress_cnt);
+	rcomp.stat_decompress_cnt = v32;
+	v64 = atomic64_read(&alg->decompress_tlen);
+	rcomp.stat_decompress_tlen = v64;
+	v32 = atomic_read(&alg->cipher_err_cnt);
+	rcomp.stat_compress_err_cnt = v32;
+
+	if (nla_put(skb, CRYPTOCFGA_STAT_COMPRESS,
+		    sizeof(struct crypto_stat), &rcomp))
+		goto nla_put_failure;
+	return 0;
+
+nla_put_failure:
+	return -EMSGSIZE;
+}
+
+static int crypto_report_acomp(struct sk_buff *skb, struct crypto_alg *alg)
+{
+	struct crypto_stat racomp;
+	u64 v64;
+	u32 v32;
+
+	strlcpy(racomp.type, "acomp", sizeof(racomp.type));
+	v32 = atomic_read(&alg->compress_cnt);
+	racomp.stat_compress_cnt = v32;
+	v64 = atomic64_read(&alg->compress_tlen);
+	racomp.stat_compress_tlen = v64;
+	v32 = atomic_read(&alg->decompress_cnt);
+	racomp.stat_decompress_cnt = v32;
+	v64 = atomic64_read(&alg->decompress_tlen);
+	racomp.stat_decompress_tlen = v64;
+	v32 = atomic_read(&alg->cipher_err_cnt);
+	racomp.stat_compress_err_cnt = v32;
+
+	if (nla_put(skb, CRYPTOCFGA_STAT_ACOMP,
+		    sizeof(struct crypto_stat), &racomp))
+		goto nla_put_failure;
+	return 0;
+
+nla_put_failure:
+	return -EMSGSIZE;
+}
+
+static int crypto_report_akcipher(struct sk_buff *skb, struct crypto_alg *alg)
+{
+	struct crypto_stat rakcipher;
+	u64 v64;
+	u32 v32;
+
+	strncpy(rakcipher.type, "akcipher", sizeof(rakcipher.type));
+	v32 = atomic_read(&alg->encrypt_cnt);
+	rakcipher.stat_encrypt_cnt = v32;
+	v64 = atomic64_read(&alg->encrypt_tlen);
+	rakcipher.stat_encrypt_tlen = v64;
+	v32 = atomic_read(&alg->decrypt_cnt);
+	rakcipher.stat_decrypt_cnt = v32;
+	v64 = atomic64_read(&alg->decrypt_tlen);
+	rakcipher.stat_decrypt_tlen = v64;
+	v32 = atomic_read(&alg->sign_cnt);
+	rakcipher.stat_sign_cnt = v32;
+	v32 = atomic_read(&alg->verify_cnt);
+	rakcipher.stat_verify_cnt = v32;
+	v32 = atomic_read(&alg->akcipher_err_cnt);
+	rakcipher.stat_akcipher_err_cnt = v32;
+
+	if (nla_put(skb, CRYPTOCFGA_STAT_AKCIPHER,
+		    sizeof(struct crypto_stat), &rakcipher))
+		goto nla_put_failure;
+	return 0;
+
+nla_put_failure:
+	return -EMSGSIZE;
+}
+
+static int crypto_report_kpp(struct sk_buff *skb, struct crypto_alg *alg)
+{
+	struct crypto_stat rkpp;
+	u32 v;
+
+	strlcpy(rkpp.type, "kpp", sizeof(rkpp.type));
+
+	v = atomic_read(&alg->setsecret_cnt);
+	rkpp.stat_setsecret_cnt = v;
+	v = atomic_read(&alg->generate_public_key_cnt);
+	rkpp.stat_generate_public_key_cnt = v;
+	v = atomic_read(&alg->compute_shared_secret_cnt);
+	rkpp.stat_compute_shared_secret_cnt = v;
+	v = atomic_read(&alg->kpp_err_cnt);
+	rkpp.stat_kpp_err_cnt = v;
+
+	if (nla_put(skb, CRYPTOCFGA_STAT_KPP,
+		    sizeof(struct crypto_stat), &rkpp))
+		goto nla_put_failure;
+	return 0;
+
+nla_put_failure:
+	return -EMSGSIZE;
+}
+
+static int crypto_report_ahash(struct sk_buff *skb, struct crypto_alg *alg)
+{
+	struct crypto_stat rhash;
+	u64 v64;
+	u32 v32;
+
+	strncpy(rhash.type, "ahash", sizeof(rhash.type));
+
+	v32 = atomic_read(&alg->hash_cnt);
+	rhash.stat_hash_cnt = v32;
+	v64 = atomic64_read(&alg->hash_tlen);
+	rhash.stat_hash_tlen = v64;
+	v32 = atomic_read(&alg->hash_err_cnt);
+	rhash.stat_hash_err_cnt = v32;
+
+	if (nla_put(skb, CRYPTOCFGA_STAT_HASH,
+		    sizeof(struct crypto_stat), &rhash))
+		goto nla_put_failure;
+	return 0;
+
+nla_put_failure:
+	return -EMSGSIZE;
+}
+
+static int crypto_report_shash(struct sk_buff *skb, struct crypto_alg *alg)
+{
+	struct crypto_stat rhash;
+	u64 v64;
+	u32 v32;
+
+	strncpy(rhash.type, "shash", sizeof(rhash.type));
+
+	v32 = atomic_read(&alg->hash_cnt);
+	rhash.stat_hash_cnt = v32;
+	v64 = atomic64_read(&alg->hash_tlen);
+	rhash.stat_hash_tlen = v64;
+	v32 = atomic_read(&alg->hash_err_cnt);
+	rhash.stat_hash_err_cnt = v32;
+
+	if (nla_put(skb, CRYPTOCFGA_STAT_HASH,
+		    sizeof(struct crypto_stat), &rhash))
+		goto nla_put_failure;
+	return 0;
+
+nla_put_failure:
+	return -EMSGSIZE;
+}
+
+static int crypto_report_rng(struct sk_buff *skb, struct crypto_alg *alg)
+{
+	struct crypto_stat rrng;
+	u64 v64;
+	u32 v32;
+
+	strncpy(rrng.type, "rng", sizeof(rrng.type));
+
+	v32 = atomic_read(&alg->generate_cnt);
+	rrng.stat_generate_cnt = v32;
+	v64 = atomic64_read(&alg->generate_tlen);
+	rrng.stat_generate_tlen = v64;
+	v32 = atomic_read(&alg->seed_cnt);
+	rrng.stat_seed_cnt = v32;
+	v32 = atomic_read(&alg->hash_err_cnt);
+	rrng.stat_rng_err_cnt = v32;
+
+	if (nla_put(skb, CRYPTOCFGA_STAT_RNG,
+		    sizeof(struct crypto_stat), &rrng))
+		goto nla_put_failure;
+	return 0;
+
+nla_put_failure:
+	return -EMSGSIZE;
+}
+
+static int crypto_reportstat_one(struct crypto_alg *alg,
+				 struct crypto_user_alg *ualg,
+				 struct sk_buff *skb)
+{
+	strlcpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name));
+	strlcpy(ualg->cru_driver_name, alg->cra_driver_name,
+		sizeof(ualg->cru_driver_name));
+	strlcpy(ualg->cru_module_name, module_name(alg->cra_module),
+		sizeof(ualg->cru_module_name));
+
+	ualg->cru_type = 0;
+	ualg->cru_mask = 0;
+	ualg->cru_flags = alg->cra_flags;
+	ualg->cru_refcnt = refcount_read(&alg->cra_refcnt);
+
+	if (nla_put_u32(skb, CRYPTOCFGA_PRIORITY_VAL, alg->cra_priority))
+		goto nla_put_failure;
+	if (alg->cra_flags & CRYPTO_ALG_LARVAL) {
+		struct crypto_stat rl;
+
+		strlcpy(rl.type, "larval", sizeof(rl.type));
+		if (nla_put(skb, CRYPTOCFGA_STAT_LARVAL,
+			    sizeof(struct crypto_stat), &rl))
+			goto nla_put_failure;
+		goto out;
+	}
+
+	switch (alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL)) {
+	case CRYPTO_ALG_TYPE_AEAD:
+		if (crypto_report_aead(skb, alg))
+			goto nla_put_failure;
+		break;
+	case CRYPTO_ALG_TYPE_SKCIPHER:
+		if (crypto_report_cipher(skb, alg))
+			goto nla_put_failure;
+		break;
+	case CRYPTO_ALG_TYPE_BLKCIPHER:
+		if (crypto_report_cipher(skb, alg))
+			goto nla_put_failure;
+		break;
+	case CRYPTO_ALG_TYPE_CIPHER:
+		if (crypto_report_cipher(skb, alg))
+			goto nla_put_failure;
+		break;
+	case CRYPTO_ALG_TYPE_COMPRESS:
+		if (crypto_report_comp(skb, alg))
+			goto nla_put_failure;
+		break;
+	case CRYPTO_ALG_TYPE_ACOMPRESS:
+		if (crypto_report_acomp(skb, alg))
+			goto nla_put_failure;
+		break;
+	case CRYPTO_ALG_TYPE_SCOMPRESS:
+		if (crypto_report_acomp(skb, alg))
+			goto nla_put_failure;
+		break;
+	case CRYPTO_ALG_TYPE_AKCIPHER:
+		if (crypto_report_akcipher(skb, alg))
+			goto nla_put_failure;
+		break;
+	case CRYPTO_ALG_TYPE_KPP:
+		if (crypto_report_kpp(skb, alg))
+			goto nla_put_failure;
+		break;
+	case CRYPTO_ALG_TYPE_AHASH:
+		if (crypto_report_ahash(skb, alg))
+			goto nla_put_failure;
+		break;
+	case CRYPTO_ALG_TYPE_HASH:
+		if (crypto_report_shash(skb, alg))
+			goto nla_put_failure;
+		break;
+	case CRYPTO_ALG_TYPE_RNG:
+		if (crypto_report_rng(skb, alg))
+			goto nla_put_failure;
+		break;
+	default:
+		pr_err("ERROR: Unhandled alg %d in %s\n",
+		       alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL),
+		       __func__);
+	}
+
+out:
+	return 0;
+
+nla_put_failure:
+	return -EMSGSIZE;
+}
+
+static int crypto_reportstat_alg(struct crypto_alg *alg,
+				 struct crypto_dump_info *info)
+{
+	struct sk_buff *in_skb = info->in_skb;
+	struct sk_buff *skb = info->out_skb;
+	struct nlmsghdr *nlh;
+	struct crypto_user_alg *ualg;
+	int err = 0;
+
+	nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, info->nlmsg_seq,
+			CRYPTO_MSG_GETSTAT, sizeof(*ualg), info->nlmsg_flags);
+	if (!nlh) {
+		err = -EMSGSIZE;
+		goto out;
+	}
+
+	ualg = nlmsg_data(nlh);
+
+	err = crypto_reportstat_one(alg, ualg, skb);
+	if (err) {
+		nlmsg_cancel(skb, nlh);
+		goto out;
+	}
+
+	nlmsg_end(skb, nlh);
+
+out:
+	return err;
+}
+
+int crypto_reportstat(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
+		      struct nlattr **attrs)
+{
+	struct crypto_user_alg *p = nlmsg_data(in_nlh);
+	struct crypto_alg *alg;
+	struct sk_buff *skb;
+	struct crypto_dump_info info;
+	int err;
+
+	if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
+		return -EINVAL;
+
+	alg = crypto_alg_match(p, 0);
+	if (!alg)
+		return -ENOENT;
+
+	err = -ENOMEM;
+	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+	if (!skb)
+		goto drop_alg;
+
+	info.in_skb = in_skb;
+	info.out_skb = skb;
+	info.nlmsg_seq = in_nlh->nlmsg_seq;
+	info.nlmsg_flags = 0;
+
+	err = crypto_reportstat_alg(alg, &info);
+
+drop_alg:
+	crypto_mod_put(alg);
+
+	if (err)
+		return err;
+
+	return nlmsg_unicast(crypto_nlsk, skb, NETLINK_CB(in_skb).portid);
+}
+
+int crypto_dump_reportstat(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct crypto_alg *alg;
+	struct crypto_dump_info info;
+	int err;
+
+	if (cb->args[0])
+		goto out;
+
+	cb->args[0] = 1;
+
+	info.in_skb = cb->skb;
+	info.out_skb = skb;
+	info.nlmsg_seq = cb->nlh->nlmsg_seq;
+	info.nlmsg_flags = NLM_F_MULTI;
+
+	list_for_each_entry(alg, &crypto_alg_list, cra_list) {
+		err = crypto_reportstat_alg(alg, &info);
+		if (err)
+			goto out_err;
+	}
+
+out:
+	return skb->len;
+out_err:
+	return err;
+}
+
+int crypto_dump_reportstat_done(struct netlink_callback *cb)
+{
+	return 0;
+}
+
+MODULE_LICENSE("GPL");
diff --git a/crypto/rng.c b/crypto/rng.c
index b4a618668161..547f16ecbfb0 100644
--- a/crypto/rng.c
+++ b/crypto/rng.c
@@ -50,6 +50,7 @@ int crypto_rng_reset(struct crypto_rng *tfm, const u8 *seed, unsigned int slen)
 	}
 
 	err = crypto_rng_alg(tfm)->seed(tfm, seed, slen);
+	crypto_stat_rng_seed(tfm, err);
 out:
 	kzfree(buf);
 	return err;
diff --git a/include/crypto/acompress.h b/include/crypto/acompress.h
index e328b52425a8..22e6f412c595 100644
--- a/include/crypto/acompress.h
+++ b/include/crypto/acompress.h
@@ -234,6 +234,34 @@ static inline void acomp_request_set_params(struct acomp_req *req,
 		req->flags |= CRYPTO_ACOMP_ALLOC_OUTPUT;
 }
 
+static inline void crypto_stat_compress(struct acomp_req *req, int ret)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	struct crypto_acomp *tfm = crypto_acomp_reqtfm(req);
+
+	if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
+		atomic_inc(&tfm->base.__crt_alg->compress_err_cnt);
+	} else {
+		atomic_inc(&tfm->base.__crt_alg->compress_cnt);
+		atomic64_add(req->slen, &tfm->base.__crt_alg->compress_tlen);
+	}
+#endif
+}
+
+static inline void crypto_stat_decompress(struct acomp_req *req, int ret)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	struct crypto_acomp *tfm = crypto_acomp_reqtfm(req);
+
+	if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
+		atomic_inc(&tfm->base.__crt_alg->compress_err_cnt);
+	} else {
+		atomic_inc(&tfm->base.__crt_alg->decompress_cnt);
+		atomic64_add(req->slen, &tfm->base.__crt_alg->decompress_tlen);
+	}
+#endif
+}
+
 /**
  * crypto_acomp_compress() -- Invoke asynchronous compress operation
  *
@@ -246,8 +274,11 @@ static inline void acomp_request_set_params(struct acomp_req *req,
 static inline int crypto_acomp_compress(struct acomp_req *req)
 {
 	struct crypto_acomp *tfm = crypto_acomp_reqtfm(req);
+	int ret;
 
-	return tfm->compress(req);
+	ret = tfm->compress(req);
+	crypto_stat_compress(req, ret);
+	return ret;
 }
 
 /**
@@ -262,8 +293,11 @@ static inline int crypto_acomp_compress(struct acomp_req *req)
 static inline int crypto_acomp_decompress(struct acomp_req *req)
 {
 	struct crypto_acomp *tfm = crypto_acomp_reqtfm(req);
+	int ret;
 
-	return tfm->decompress(req);
+	ret = tfm->decompress(req);
+	crypto_stat_decompress(req, ret);
+	return ret;
 }
 
 #endif
diff --git a/include/crypto/aead.h b/include/crypto/aead.h
index 1e26f790b03f..0d765d7bfb82 100644
--- a/include/crypto/aead.h
+++ b/include/crypto/aead.h
@@ -306,6 +306,34 @@ static inline struct crypto_aead *crypto_aead_reqtfm(struct aead_request *req)
 	return __crypto_aead_cast(req->base.tfm);
 }
 
+static inline void crypto_stat_aead_encrypt(struct aead_request *req, int ret)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+
+	if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
+		atomic_inc(&tfm->base.__crt_alg->aead_err_cnt);
+	} else {
+		atomic_inc(&tfm->base.__crt_alg->encrypt_cnt);
+		atomic64_add(req->cryptlen, &tfm->base.__crt_alg->encrypt_tlen);
+	}
+#endif
+}
+
+static inline void crypto_stat_aead_decrypt(struct aead_request *req, int ret)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+
+	if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
+		atomic_inc(&tfm->base.__crt_alg->aead_err_cnt);
+	} else {
+		atomic_inc(&tfm->base.__crt_alg->decrypt_cnt);
+		atomic64_add(req->cryptlen, &tfm->base.__crt_alg->decrypt_tlen);
+	}
+#endif
+}
+
 /**
  * crypto_aead_encrypt() - encrypt plaintext
  * @req: reference to the aead_request handle that holds all information
@@ -328,11 +356,14 @@ static inline struct crypto_aead *crypto_aead_reqtfm(struct aead_request *req)
 static inline int crypto_aead_encrypt(struct aead_request *req)
 {
 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	int ret;
 
 	if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY)
-		return -ENOKEY;
-
-	return crypto_aead_alg(aead)->encrypt(req);
+		ret = -ENOKEY;
+	else
+		ret = crypto_aead_alg(aead)->encrypt(req);
+	crypto_stat_aead_encrypt(req, ret);
+	return ret;
 }
 
 /**
@@ -360,14 +391,16 @@ static inline int crypto_aead_encrypt(struct aead_request *req)
 static inline int crypto_aead_decrypt(struct aead_request *req)
 {
 	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	int ret;
 
 	if (crypto_aead_get_flags(aead) & CRYPTO_TFM_NEED_KEY)
-		return -ENOKEY;
-
-	if (req->cryptlen < crypto_aead_authsize(aead))
-		return -EINVAL;
-
-	return crypto_aead_alg(aead)->decrypt(req);
+		ret = -ENOKEY;
+	else if (req->cryptlen < crypto_aead_authsize(aead))
+		ret = -EINVAL;
+	else
+		ret = crypto_aead_alg(aead)->decrypt(req);
+	crypto_stat_aead_decrypt(req, ret);
+	return ret;
 }
 
 /**
diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
index 8e0f752286e4..ee072a82d39d 100644
--- a/include/crypto/akcipher.h
+++ b/include/crypto/akcipher.h
@@ -271,6 +271,62 @@ static inline unsigned int crypto_akcipher_maxsize(struct crypto_akcipher *tfm)
 	return alg->max_size(tfm);
 }
 
+static inline void crypto_stat_akcipher_encrypt(struct akcipher_request *req,
+						int ret)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+
+	if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
+		atomic_inc(&tfm->base.__crt_alg->akcipher_err_cnt);
+	} else {
+		atomic_inc(&tfm->base.__crt_alg->encrypt_cnt);
+		atomic64_add(req->src_len, &tfm->base.__crt_alg->encrypt_tlen);
+	}
+#endif
+}
+
+static inline void crypto_stat_akcipher_decrypt(struct akcipher_request *req,
+						int ret)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+
+	if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
+		atomic_inc(&tfm->base.__crt_alg->akcipher_err_cnt);
+	} else {
+		atomic_inc(&tfm->base.__crt_alg->decrypt_cnt);
+		atomic64_add(req->src_len, &tfm->base.__crt_alg->decrypt_tlen);
+	}
+#endif
+}
+
+static inline void crypto_stat_akcipher_sign(struct akcipher_request *req,
+					     int ret)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+
+	if (ret && ret != -EINPROGRESS && ret != -EBUSY)
+		atomic_inc(&tfm->base.__crt_alg->akcipher_err_cnt);
+	else
+		atomic_inc(&tfm->base.__crt_alg->sign_cnt);
+#endif
+}
+
+static inline void crypto_stat_akcipher_verify(struct akcipher_request *req,
+					       int ret)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+
+	if (ret && ret != -EINPROGRESS && ret != -EBUSY)
+		atomic_inc(&tfm->base.__crt_alg->akcipher_err_cnt);
+	else
+		atomic_inc(&tfm->base.__crt_alg->verify_cnt);
+#endif
+}
+
 /**
  * crypto_akcipher_encrypt() - Invoke public key encrypt operation
  *
@@ -285,8 +341,11 @@ static inline int crypto_akcipher_encrypt(struct akcipher_request *req)
 {
 	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
 	struct akcipher_alg *alg = crypto_akcipher_alg(tfm);
+	int ret;
 
-	return alg->encrypt(req);
+	ret = alg->encrypt(req);
+	crypto_stat_akcipher_encrypt(req, ret);
+	return ret;
 }
 
 /**
@@ -303,8 +362,11 @@ static inline int crypto_akcipher_decrypt(struct akcipher_request *req)
 {
 	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
 	struct akcipher_alg *alg = crypto_akcipher_alg(tfm);
+	int ret;
 
-	return alg->decrypt(req);
+	ret = alg->decrypt(req);
+	crypto_stat_akcipher_decrypt(req, ret);
+	return ret;
 }
 
 /**
@@ -321,8 +383,11 @@ static inline int crypto_akcipher_sign(struct akcipher_request *req)
 {
 	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
 	struct akcipher_alg *alg = crypto_akcipher_alg(tfm);
+	int ret;
 
-	return alg->sign(req);
+	ret = alg->sign(req);
+	crypto_stat_akcipher_sign(req, ret);
+	return ret;
 }
 
 /**
@@ -339,8 +404,11 @@ static inline int crypto_akcipher_verify(struct akcipher_request *req)
 {
 	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
 	struct akcipher_alg *alg = crypto_akcipher_alg(tfm);
+	int ret;
 
-	return alg->verify(req);
+	ret = alg->verify(req);
+	crypto_stat_akcipher_verify(req, ret);
+	return ret;
 }
 
 /**
diff --git a/include/crypto/hash.h b/include/crypto/hash.h
index 21587011ab0f..bc7796600338 100644
--- a/include/crypto/hash.h
+++ b/include/crypto/hash.h
@@ -412,6 +412,32 @@ static inline void *ahash_request_ctx(struct ahash_request *req)
 int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
 			unsigned int keylen);
 
+static inline void crypto_stat_ahash_update(struct ahash_request *req, int ret)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+
+	if (ret && ret != -EINPROGRESS && ret != -EBUSY)
+		atomic_inc(&tfm->base.__crt_alg->hash_err_cnt);
+	else
+		atomic64_add(req->nbytes, &tfm->base.__crt_alg->hash_tlen);
+#endif
+}
+
+static inline void crypto_stat_ahash_final(struct ahash_request *req, int ret)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+
+	if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
+		atomic_inc(&tfm->base.__crt_alg->hash_err_cnt);
+	} else {
+		atomic_inc(&tfm->base.__crt_alg->hash_cnt);
+		atomic64_add(req->nbytes, &tfm->base.__crt_alg->hash_tlen);
+	}
+#endif
+}
+
 /**
  * crypto_ahash_finup() - update and finalize message digest
  * @req: reference to the ahash_request handle that holds all information
@@ -526,7 +552,11 @@ static inline int crypto_ahash_init(struct ahash_request *req)
  */
 static inline int crypto_ahash_update(struct ahash_request *req)
 {
-	return crypto_ahash_reqtfm(req)->update(req);
+	int ret;
+
+	ret = crypto_ahash_reqtfm(req)->update(req);
+	crypto_stat_ahash_update(req, ret);
+	return ret;
 }
 
 /**
diff --git a/include/crypto/internal/cryptouser.h b/include/crypto/internal/cryptouser.h
new file mode 100644
index 000000000000..8db299c25566
--- /dev/null
+++ b/include/crypto/internal/cryptouser.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <net/netlink.h>
+
+struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact);
+
+int crypto_dump_reportstat(struct sk_buff *skb, struct netlink_callback *cb);
+int crypto_reportstat(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, struct nlattr **attrs);
+int crypto_dump_reportstat_done(struct netlink_callback *cb);
diff --git a/include/crypto/kpp.h b/include/crypto/kpp.h
index 1bde0a6514fa..f517ba6d3a27 100644
--- a/include/crypto/kpp.h
+++ b/include/crypto/kpp.h
@@ -268,6 +268,42 @@ struct kpp_secret {
 	unsigned short len;
 };
 
+static inline void crypto_stat_kpp_set_secret(struct crypto_kpp *tfm, int ret)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	if (ret)
+		atomic_inc(&tfm->base.__crt_alg->kpp_err_cnt);
+	else
+		atomic_inc(&tfm->base.__crt_alg->setsecret_cnt);
+#endif
+}
+
+static inline void crypto_stat_kpp_generate_public_key(struct kpp_request *req,
+						       int ret)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
+
+	if (ret)
+		atomic_inc(&tfm->base.__crt_alg->kpp_err_cnt);
+	else
+		atomic_inc(&tfm->base.__crt_alg->generate_public_key_cnt);
+#endif
+}
+
+static inline void crypto_stat_kpp_compute_shared_secret(struct kpp_request *req,
+							 int ret)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
+
+	if (ret)
+		atomic_inc(&tfm->base.__crt_alg->kpp_err_cnt);
+	else
+		atomic_inc(&tfm->base.__crt_alg->compute_shared_secret_cnt);
+#endif
+}
+
 /**
  * crypto_kpp_set_secret() - Invoke kpp operation
  *
@@ -287,8 +323,11 @@ static inline int crypto_kpp_set_secret(struct crypto_kpp *tfm,
 					const void *buffer, unsigned int len)
 {
 	struct kpp_alg *alg = crypto_kpp_alg(tfm);
+	int ret;
 
-	return alg->set_secret(tfm, buffer, len);
+	ret = alg->set_secret(tfm, buffer, len);
+	crypto_stat_kpp_set_secret(tfm, ret);
+	return ret;
 }
 
 /**
@@ -308,8 +347,11 @@ static inline int crypto_kpp_generate_public_key(struct kpp_request *req)
 {
 	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
 	struct kpp_alg *alg = crypto_kpp_alg(tfm);
+	int ret;
 
-	return alg->generate_public_key(req);
+	ret = alg->generate_public_key(req);
+	crypto_stat_kpp_generate_public_key(req, ret);
+	return ret;
 }
 
 /**
@@ -326,8 +368,11 @@ static inline int crypto_kpp_compute_shared_secret(struct kpp_request *req)
 {
 	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
 	struct kpp_alg *alg = crypto_kpp_alg(tfm);
+	int ret;
 
-	return alg->compute_shared_secret(req);
+	ret = alg->compute_shared_secret(req);
+	crypto_stat_kpp_compute_shared_secret(req, ret);
+	return ret;
 }
 
 /**
diff --git a/include/crypto/rng.h b/include/crypto/rng.h
index 42811936a361..0d781fa77161 100644
--- a/include/crypto/rng.h
+++ b/include/crypto/rng.h
@@ -122,6 +122,29 @@ static inline void crypto_free_rng(struct crypto_rng *tfm)
 	crypto_destroy_tfm(tfm, crypto_rng_tfm(tfm));
 }
 
+static inline void crypto_stat_rng_seed(struct crypto_rng *tfm, int ret)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	if (ret && ret != -EINPROGRESS && ret != -EBUSY)
+		atomic_inc(&tfm->base.__crt_alg->rng_err_cnt);
+	else
+		atomic_inc(&tfm->base.__crt_alg->seed_cnt);
+#endif
+}
+
+static inline void crypto_stat_rng_generate(struct crypto_rng *tfm,
+					    unsigned int dlen, int ret)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
+		atomic_inc(&tfm->base.__crt_alg->rng_err_cnt);
+	} else {
+		atomic_inc(&tfm->base.__crt_alg->generate_cnt);
+		atomic64_add(dlen, &tfm->base.__crt_alg->generate_tlen);
+	}
+#endif
+}
+
 /**
  * crypto_rng_generate() - get random number
  * @tfm: cipher handle
@@ -140,7 +163,11 @@ static inline int crypto_rng_generate(struct crypto_rng *tfm,
 				      const u8 *src, unsigned int slen,
 				      u8 *dst, unsigned int dlen)
 {
-	return crypto_rng_alg(tfm)->generate(tfm, src, slen, dst, dlen);
+	int ret;
+
+	ret = crypto_rng_alg(tfm)->generate(tfm, src, slen, dst, dlen);
+	crypto_stat_rng_generate(tfm, dlen, ret);
+	return ret;
 }
 
 /**
diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h
index 2f327f090c3e..ffa3df325ca3 100644
--- a/include/crypto/skcipher.h
+++ b/include/crypto/skcipher.h
@@ -422,6 +422,32 @@ static inline struct crypto_skcipher *crypto_skcipher_reqtfm(
 	return __crypto_skcipher_cast(req->base.tfm);
 }
 
+static inline void crypto_stat_skcipher_encrypt(struct skcipher_request *req,
+						int ret, struct crypto_alg *alg)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
+		atomic_inc(&alg->cipher_err_cnt);
+	} else {
+		atomic_inc(&alg->encrypt_cnt);
+		atomic64_add(req->cryptlen, &alg->encrypt_tlen);
+	}
+#endif
+}
+
+static inline void crypto_stat_skcipher_decrypt(struct skcipher_request *req,
+						int ret, struct crypto_alg *alg)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
+		atomic_inc(&alg->cipher_err_cnt);
+	} else {
+		atomic_inc(&alg->decrypt_cnt);
+		atomic64_add(req->cryptlen, &alg->decrypt_tlen);
+	}
+#endif
+}
+
 /**
  * crypto_skcipher_encrypt() - encrypt plaintext
  * @req: reference to the skcipher_request handle that holds all information
@@ -436,11 +462,14 @@ static inline struct crypto_skcipher *crypto_skcipher_reqtfm(
 static inline int crypto_skcipher_encrypt(struct skcipher_request *req)
 {
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+	int ret;
 
 	if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
-		return -ENOKEY;
-
-	return tfm->encrypt(req);
+		ret = -ENOKEY;
+	else
+		ret = tfm->encrypt(req);
+	crypto_stat_skcipher_encrypt(req, ret, tfm->base.__crt_alg);
+	return ret;
 }
 
 /**
@@ -457,11 +486,14 @@ static inline int crypto_skcipher_encrypt(struct skcipher_request *req)
 static inline int crypto_skcipher_decrypt(struct skcipher_request *req)
 {
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+	int ret;
 
 	if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
-		return -ENOKEY;
-
-	return tfm->decrypt(req);
+		ret = -ENOKEY;
+	else
+		ret = tfm->decrypt(req);
+	crypto_stat_skcipher_decrypt(req, ret, tfm->base.__crt_alg);
+	return ret;
 }
 
 /**
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index e8839d3a7559..3634ad6fe202 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -454,6 +454,33 @@ struct compress_alg {
  * @cra_refcnt: internally used
  * @cra_destroy: internally used
  *
+ * All following statistics are for this crypto_alg
+ * @encrypt_cnt:	number of encrypt requests
+ * @decrypt_cnt:	number of decrypt requests
+ * @compress_cnt:	number of compress requests
+ * @decompress_cnt:	number of decompress requests
+ * @generate_cnt:	number of RNG generate requests
+ * @seed_cnt:		number of times the rng was seeded
+ * @hash_cnt:		number of hash requests
+ * @sign_cnt:		number of sign requests
+ * @setsecret_cnt:	number of setsecrey operation
+ * @generate_public_key_cnt:	number of generate_public_key operation
+ * @verify_cnt:			number of verify operation
+ * @compute_shared_secret_cnt:	number of compute_shared_secret operation
+ * @encrypt_tlen:	total data size handled by encrypt requests
+ * @decrypt_tlen:	total data size handled by decrypt requests
+ * @compress_tlen:	total data size handled by compress requests
+ * @decompress_tlen:	total data size handled by decompress requests
+ * @generate_tlen:	total data size of generated data by the RNG
+ * @hash_tlen:		total data size hashed
+ * @akcipher_err_cnt:	number of error for akcipher requests
+ * @cipher_err_cnt:	number of error for akcipher requests
+ * @compress_err_cnt:	number of error for akcipher requests
+ * @aead_err_cnt:	number of error for akcipher requests
+ * @hash_err_cnt:	number of error for akcipher requests
+ * @rng_err_cnt:	number of error for akcipher requests
+ * @kpp_err_cnt:	number of error for akcipher requests
+ *
  * The struct crypto_alg describes a generic Crypto API algorithm and is common
  * for all of the transformations. Any variable not documented here shall not
  * be used by a cipher implementation as it is internal to the Crypto API.
@@ -487,6 +514,45 @@ struct crypto_alg {
 	void (*cra_destroy)(struct crypto_alg *alg);
 	
 	struct module *cra_module;
+
+	union {
+		atomic_t encrypt_cnt;
+		atomic_t compress_cnt;
+		atomic_t generate_cnt;
+		atomic_t hash_cnt;
+		atomic_t setsecret_cnt;
+	};
+	union {
+		atomic64_t encrypt_tlen;
+		atomic64_t compress_tlen;
+		atomic64_t generate_tlen;
+		atomic64_t hash_tlen;
+	};
+	union {
+		atomic_t akcipher_err_cnt;
+		atomic_t cipher_err_cnt;
+		atomic_t compress_err_cnt;
+		atomic_t aead_err_cnt;
+		atomic_t hash_err_cnt;
+		atomic_t rng_err_cnt;
+		atomic_t kpp_err_cnt;
+	};
+	union {
+		atomic_t decrypt_cnt;
+		atomic_t decompress_cnt;
+		atomic_t seed_cnt;
+		atomic_t generate_public_key_cnt;
+	};
+	union {
+		atomic64_t decrypt_tlen;
+		atomic64_t decompress_tlen;
+	};
+	union {
+		atomic_t verify_cnt;
+		atomic_t compute_shared_secret_cnt;
+	};
+	atomic_t sign_cnt;
+
 } CRYPTO_MINALIGN_ATTR;
 
 /*
@@ -907,6 +973,38 @@ static inline struct crypto_ablkcipher *crypto_ablkcipher_reqtfm(
 	return __crypto_ablkcipher_cast(req->base.tfm);
 }
 
+static inline void crypto_stat_ablkcipher_encrypt(struct ablkcipher_request *req,
+						  int ret)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	struct ablkcipher_tfm *crt =
+		crypto_ablkcipher_crt(crypto_ablkcipher_reqtfm(req));
+
+	if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
+		atomic_inc(&crt->base->base.__crt_alg->cipher_err_cnt);
+	} else {
+		atomic_inc(&crt->base->base.__crt_alg->encrypt_cnt);
+		atomic64_add(req->nbytes, &crt->base->base.__crt_alg->encrypt_tlen);
+	}
+#endif
+}
+
+static inline void crypto_stat_ablkcipher_decrypt(struct ablkcipher_request *req,
+						  int ret)
+{
+#ifdef CONFIG_CRYPTO_STATS
+	struct ablkcipher_tfm *crt =
+		crypto_ablkcipher_crt(crypto_ablkcipher_reqtfm(req));
+
+	if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
+		atomic_inc(&crt->base->base.__crt_alg->cipher_err_cnt);
+	} else {
+		atomic_inc(&crt->base->base.__crt_alg->decrypt_cnt);
+		atomic64_add(req->nbytes, &crt->base->base.__crt_alg->decrypt_tlen);
+	}
+#endif
+}
+
 /**
  * crypto_ablkcipher_encrypt() - encrypt plaintext
  * @req: reference to the ablkcipher_request handle that holds all information
@@ -922,7 +1020,11 @@ static inline int crypto_ablkcipher_encrypt(struct ablkcipher_request *req)
 {
 	struct ablkcipher_tfm *crt =
 		crypto_ablkcipher_crt(crypto_ablkcipher_reqtfm(req));
-	return crt->encrypt(req);
+	int ret;
+
+	ret = crt->encrypt(req);
+	crypto_stat_ablkcipher_encrypt(req, ret);
+	return ret;
 }
 
 /**
@@ -940,7 +1042,11 @@ static inline int crypto_ablkcipher_decrypt(struct ablkcipher_request *req)
 {
 	struct ablkcipher_tfm *crt =
 		crypto_ablkcipher_crt(crypto_ablkcipher_reqtfm(req));
-	return crt->decrypt(req);
+	int ret;
+
+	ret = crt->decrypt(req);
+	crypto_stat_ablkcipher_decrypt(req, ret);
+	return ret;
 }
 
 /**
diff --git a/include/uapi/linux/cryptouser.h b/include/uapi/linux/cryptouser.h
index 19bf0ca6d635..6dafbc3e4414 100644
--- a/include/uapi/linux/cryptouser.h
+++ b/include/uapi/linux/cryptouser.h
@@ -29,6 +29,7 @@ enum {
 	CRYPTO_MSG_UPDATEALG,
 	CRYPTO_MSG_GETALG,
 	CRYPTO_MSG_DELRNG,
+	CRYPTO_MSG_GETSTAT,
 	__CRYPTO_MSG_MAX
 };
 #define CRYPTO_MSG_MAX (__CRYPTO_MSG_MAX - 1)
@@ -50,6 +51,16 @@ enum crypto_attr_type_t {
 	CRYPTOCFGA_REPORT_AKCIPHER,	/* struct crypto_report_akcipher */
 	CRYPTOCFGA_REPORT_KPP,		/* struct crypto_report_kpp */
 	CRYPTOCFGA_REPORT_ACOMP,	/* struct crypto_report_acomp */
+	CRYPTOCFGA_STAT_LARVAL,		/* struct crypto_stat */
+	CRYPTOCFGA_STAT_HASH,		/* struct crypto_stat */
+	CRYPTOCFGA_STAT_BLKCIPHER,	/* struct crypto_stat */
+	CRYPTOCFGA_STAT_AEAD,		/* struct crypto_stat */
+	CRYPTOCFGA_STAT_COMPRESS,	/* struct crypto_stat */
+	CRYPTOCFGA_STAT_RNG,		/* struct crypto_stat */
+	CRYPTOCFGA_STAT_CIPHER,		/* struct crypto_stat */
+	CRYPTOCFGA_STAT_AKCIPHER,	/* struct crypto_stat */
+	CRYPTOCFGA_STAT_KPP,		/* struct crypto_stat */
+	CRYPTOCFGA_STAT_ACOMP,		/* struct crypto_stat */
 	__CRYPTOCFGA_MAX
 
 #define CRYPTOCFGA_MAX (__CRYPTOCFGA_MAX - 1)
@@ -65,6 +76,47 @@ struct crypto_user_alg {
 	__u32 cru_flags;
 };
 
+struct crypto_stat {
+	char type[CRYPTO_MAX_NAME];
+	union {
+		__u32 stat_encrypt_cnt;
+		__u32 stat_compress_cnt;
+		__u32 stat_generate_cnt;
+		__u32 stat_hash_cnt;
+		__u32 stat_setsecret_cnt;
+	};
+	union {
+		__u64 stat_encrypt_tlen;
+		__u64 stat_compress_tlen;
+		__u64 stat_generate_tlen;
+		__u64 stat_hash_tlen;
+	};
+	union {
+		__u32 stat_akcipher_err_cnt;
+		__u32 stat_cipher_err_cnt;
+		__u32 stat_compress_err_cnt;
+		__u32 stat_aead_err_cnt;
+		__u32 stat_hash_err_cnt;
+		__u32 stat_rng_err_cnt;
+		__u32 stat_kpp_err_cnt;
+	};
+	union {
+		__u32 stat_decrypt_cnt;
+		__u32 stat_decompress_cnt;
+		__u32 stat_seed_cnt;
+		__u32 stat_generate_public_key_cnt;
+	};
+	union {
+		__u64 stat_decrypt_tlen;
+		__u64 stat_decompress_tlen;
+	};
+	union {
+		__u32 stat_verify_cnt;
+		__u32 stat_compute_shared_secret_cnt;
+	};
+	__u32 stat_sign_cnt;
+};
+
 struct crypto_report_larval {
 	char type[CRYPTO_MAX_NAME];
 };
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v3 2/2] crypto: tools: Add cryptostat userspace
  2018-09-19 10:10 [PATCH v3 0/2] crypto: Implement a generic crypto statistics Corentin Labbe
  2018-09-19 10:10 ` [PATCH v3 1/2] " Corentin Labbe
@ 2018-09-19 10:10 ` Corentin Labbe
  2018-09-28 13:13     ` Ard Biesheuvel
  2018-09-28  5:08 ` [PATCH v3 0/2] crypto: Implement a generic crypto statistics Herbert Xu
  2 siblings, 1 reply; 18+ messages in thread
From: Corentin Labbe @ 2018-09-19 10:10 UTC (permalink / raw)
  To: davem, herbert, nhorman; +Cc: linux-crypto, linux-kernel, Corentin Labbe

This patch adds an userspace tool for displaying kernel crypto API
statistics.

Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
---
 tools/crypto/getstat.c | 294 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 294 insertions(+)
 create mode 100644 tools/crypto/getstat.c

diff --git a/tools/crypto/getstat.c b/tools/crypto/getstat.c
new file mode 100644
index 000000000000..24115173a483
--- /dev/null
+++ b/tools/crypto/getstat.c
@@ -0,0 +1,294 @@
+/* Heavily copied from libkcapi 2015 - 2017, Stephan Mueller <smueller@chronox.de> */
+#include <errno.h>
+#include <linux/cryptouser.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define CR_RTA(x)  ((struct rtattr *)(((char *)(x)) + NLMSG_ALIGN(sizeof(struct crypto_user_alg))))
+
+static int get_stat(const char *drivername)
+{
+	struct {
+		struct nlmsghdr n;
+		struct crypto_user_alg cru;
+	} req;
+	struct sockaddr_nl nl;
+	int sd = 0, ret;
+	socklen_t addr_len;
+	struct iovec iov;
+	struct msghdr msg;
+	char buf[4096];
+	struct nlmsghdr *res_n = (struct nlmsghdr *)buf;
+	struct crypto_user_alg *cru_res = NULL;
+	int res_len = 0;
+	struct rtattr *tb[CRYPTOCFGA_MAX + 1];
+	struct rtattr *rta;
+	struct nlmsgerr *errmsg;
+
+	memset(&req, 0, sizeof(req));
+	memset(&buf, 0, sizeof(buf));
+	memset(&msg, 0, sizeof(msg));
+
+	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.cru));
+	req.n.nlmsg_flags = NLM_F_REQUEST;
+	req.n.nlmsg_type = CRYPTO_MSG_GETSTAT;
+	req.n.nlmsg_seq = time(NULL);
+
+	strncpy(req.cru.cru_driver_name, drivername, strlen(drivername));
+
+	sd =  socket(AF_NETLINK, SOCK_RAW, NETLINK_CRYPTO);
+	if (sd < 0) {
+		fprintf(stderr, "Netlink error: cannot open netlink socket");
+		return -errno;
+	}
+	memset(&nl, 0, sizeof(nl));
+	nl.nl_family = AF_NETLINK;
+	if (bind(sd, (struct sockaddr *)&nl, sizeof(nl)) < 0) {
+		ret = -errno;
+		fprintf(stderr, "Netlink error: cannot bind netlink socket");
+		goto out;
+	}
+
+	/* sanity check that netlink socket was successfully opened */
+	addr_len = sizeof(nl);
+	if (getsockname(sd, (struct sockaddr *)&nl, &addr_len) < 0) {
+		ret = -errno;
+		printf("Netlink error: cannot getsockname");
+		goto out;
+	}
+	if (addr_len != sizeof(nl)) {
+		ret = -errno;
+		printf("Netlink error: wrong address length %d", addr_len);
+		goto out;
+	}
+	if (nl.nl_family != AF_NETLINK) {
+		ret = -errno;
+		printf("Netlink error: wrong address family %d",
+				nl.nl_family);
+		goto out;
+	}
+
+	memset(&nl, 0, sizeof(nl));
+	nl.nl_family = AF_NETLINK;
+	iov.iov_base = (void *)&req.n;
+	iov.iov_len = req.n.nlmsg_len;
+	msg.msg_name = &nl;
+	msg.msg_namelen = sizeof(nl);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	if (sendmsg(sd, &msg, 0) < 0) {
+		ret = -errno;
+		printf("Netlink error: sendmsg failed");
+		goto out;
+	}
+	memset(buf, 0, sizeof(buf));
+	iov.iov_base = buf;
+	while (1) {
+		iov.iov_len = sizeof(buf);
+		ret = recvmsg(sd, &msg, 0);
+		if (ret < 0) {
+			if (errno == EINTR || errno == EAGAIN)
+				continue;
+			ret = -errno;
+			printf("Netlink error: netlink receive error");
+			goto out;
+		}
+		if (ret == 0) {
+			ret = -errno;
+			printf("Netlink error: no data");
+			goto out;
+		}
+		if (ret > sizeof(buf)) {
+			ret = -errno;
+			printf("Netlink error: received too much data");
+			goto out;
+		}
+		break;
+	}
+
+	ret = -EFAULT;
+	res_len = res_n->nlmsg_len;
+	if (res_n->nlmsg_type == NLMSG_ERROR) {
+		errmsg = NLMSG_DATA(res_n);
+		fprintf(stderr, "Fail with %d\n", errmsg->error);
+		ret = errmsg->error;
+		goto out;
+	}
+
+	if (res_n->nlmsg_type == CRYPTO_MSG_GETSTAT) {
+		cru_res = NLMSG_DATA(res_n);
+		res_len -= NLMSG_SPACE(sizeof(*cru_res));
+	}
+	if (res_len < 0) {
+		printf("Netlink error: nlmsg len %d\n", res_len);
+		goto out;
+	}
+
+	if (!cru_res) {
+		ret = -EFAULT;
+		printf("Netlink error: no cru_res\n");
+		goto out;
+	}
+
+	rta = CR_RTA(cru_res);
+	memset(tb, 0, sizeof(struct rtattr *) * (CRYPTOCFGA_MAX + 1));
+	while (RTA_OK(rta, res_len)) {
+		if ((rta->rta_type <= CRYPTOCFGA_MAX) && (!tb[rta->rta_type]))
+			tb[rta->rta_type] = rta;
+		rta = RTA_NEXT(rta, res_len);
+	}
+	if (res_len) {
+		printf("Netlink error: unprocessed data %d",
+				res_len);
+		goto out;
+	}
+
+	if (tb[CRYPTOCFGA_STAT_HASH]) {
+		struct rtattr *rta = tb[CRYPTOCFGA_STAT_HASH];
+		struct crypto_stat *rhash =
+			(struct crypto_stat *)RTA_DATA(rta);
+		printf("%s\tHash\n\tHash: %u bytes: %llu\n\tErrors: %u\n",
+			drivername,
+			rhash->stat_hash_cnt, rhash->stat_hash_tlen,
+			rhash->stat_hash_err_cnt);
+	} else if (tb[CRYPTOCFGA_STAT_COMPRESS]) {
+		struct rtattr *rta = tb[CRYPTOCFGA_STAT_COMPRESS];
+		struct crypto_stat *rblk =
+			(struct crypto_stat *)RTA_DATA(rta);
+		printf("%s\tCompress\n\tCompress: %u bytes: %llu\n\tDecompress: %u bytes: %llu\n\tErrors: %u\n",
+			drivername,
+			rblk->stat_compress_cnt, rblk->stat_compress_tlen,
+			rblk->stat_decompress_cnt, rblk->stat_decompress_tlen,
+			rblk->stat_compress_err_cnt);
+	} else if (tb[CRYPTOCFGA_STAT_ACOMP]) {
+		struct rtattr *rta = tb[CRYPTOCFGA_STAT_ACOMP];
+		struct crypto_stat *rcomp =
+			(struct crypto_stat *)RTA_DATA(rta);
+		printf("%s\tACompress\n\tCompress: %u bytes: %llu\n\tDecompress: %u bytes: %llu\n\tErrors: %u\n",
+			drivername,
+			rcomp->stat_compress_cnt, rcomp->stat_compress_tlen,
+			rcomp->stat_decompress_cnt, rcomp->stat_decompress_tlen,
+			rcomp->stat_compress_err_cnt);
+	} else if (tb[CRYPTOCFGA_STAT_AEAD]) {
+		struct rtattr *rta = tb[CRYPTOCFGA_STAT_AEAD];
+		struct crypto_stat *raead =
+			(struct crypto_stat *)RTA_DATA(rta);
+		printf("%s\tAEAD\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tErrors: %u\n",
+			drivername,
+			raead->stat_encrypt_cnt, raead->stat_encrypt_tlen,
+			raead->stat_decrypt_cnt, raead->stat_decrypt_tlen,
+			raead->stat_aead_err_cnt);
+	} else if (tb[CRYPTOCFGA_STAT_BLKCIPHER]) {
+		struct rtattr *rta = tb[CRYPTOCFGA_STAT_BLKCIPHER];
+		struct crypto_stat *rblk =
+			(struct crypto_stat *)RTA_DATA(rta);
+		printf("%s\tCipher\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tErrors: %u\n",
+			drivername,
+			rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen,
+			rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen,
+			rblk->stat_cipher_err_cnt);
+	} else if (tb[CRYPTOCFGA_STAT_AKCIPHER]) {
+		struct rtattr *rta = tb[CRYPTOCFGA_STAT_AKCIPHER];
+		struct crypto_stat *rblk =
+			(struct crypto_stat *)RTA_DATA(rta);
+		printf("%s\tAkcipher\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tSign: %u\n\tVerify: %u\n\tErrors: %u\n",
+			drivername,
+			rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen,
+			rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen,
+			rblk->stat_sign_cnt, rblk->stat_verify_cnt,
+			rblk->stat_akcipher_err_cnt);
+	} else if (tb[CRYPTOCFGA_STAT_CIPHER]) {
+		struct rtattr *rta = tb[CRYPTOCFGA_STAT_CIPHER];
+		struct crypto_stat *rblk =
+			(struct crypto_stat *)RTA_DATA(rta);
+		printf("%s\tcipher\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tErrors: %u\n",
+			drivername,
+			rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen,
+			rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen,
+			rblk->stat_cipher_err_cnt);
+	} else if (tb[CRYPTOCFGA_STAT_RNG]) {
+		struct rtattr *rta = tb[CRYPTOCFGA_STAT_RNG];
+		struct crypto_stat *rrng =
+			(struct crypto_stat *)RTA_DATA(rta);
+		printf("%s\tRNG\n\tSeed: %u\n\tGenerate: %u bytes: %llu\n\tErrors: %u\n",
+			drivername,
+			rrng->stat_seed_cnt,
+			rrng->stat_generate_cnt, rrng->stat_generate_tlen,
+			rrng->stat_rng_err_cnt);
+	} else if (tb[CRYPTOCFGA_STAT_KPP]) {
+		struct rtattr *rta = tb[CRYPTOCFGA_STAT_KPP];
+		struct crypto_stat *rkpp =
+			(struct crypto_stat *)RTA_DATA(rta);
+		printf("%s\tKPP\n\tSetsecret: %u\n\tGenerate public key: %u\n\tCompute_shared_secret: %u\n\tErrors: %u\n",
+			drivername,
+			rkpp->stat_setsecret_cnt,
+			rkpp->stat_generate_public_key_cnt,
+			rkpp->stat_compute_shared_secret_cnt,
+			rkpp->stat_kpp_err_cnt);
+	} else {
+		fprintf(stderr, "%s is of an unknown algorithm\n", drivername);
+	}
+	ret = 0;
+out:
+	close(sd);
+	return ret;
+}
+
+int main(int argc, const char *argv[])
+{
+	char buf[4096];
+	FILE *procfd;
+	int i, lastspace;
+	int ret;
+
+	procfd = fopen("/proc/crypto", "r");
+	if (!procfd) {
+		ret = errno;
+		fprintf(stderr, "Cannot open /proc/crypto %s\n", strerror(errno));
+		return ret;
+	}
+	if (argc > 1) {
+		if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+			printf("Usage: %s [-h|--help] display this help\n", argv[0]);
+			printf("Usage: %s display all crypto statistics\n", argv[0]);
+			printf("Usage: %s drivername1 drivername2 ... = display crypto statistics about drivername1 ...\n", argv[0]);
+			return 0;
+		}
+		for (i = 1; i < argc; i++) {
+			ret = get_stat(argv[i]);
+			if (ret) {
+				fprintf(stderr, "Failed with %s\n", strerror(-ret));
+				return ret;
+			}
+		}
+		return 0;
+	}
+
+	while (fgets(buf, sizeof(buf), procfd)) {
+		if (!strncmp(buf, "driver", 6)) {
+			lastspace = 0;
+			i = 0;
+			while (i < strlen(buf)) {
+				i++;
+				if (buf[i] == ' ')
+					lastspace = i;
+			}
+			buf[strlen(buf) - 1] = '\0';
+			ret = get_stat(buf + lastspace + 1);
+			if (ret) {
+				fprintf(stderr, "Failed with %s\n", strerror(-ret));
+				goto out;
+			}
+		}
+	}
+out:
+	fclose(procfd);
+	return ret;
+}
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 0/2] crypto: Implement a generic crypto statistics
  2018-09-19 10:10 [PATCH v3 0/2] crypto: Implement a generic crypto statistics Corentin Labbe
  2018-09-19 10:10 ` [PATCH v3 1/2] " Corentin Labbe
  2018-09-19 10:10 ` [PATCH v3 2/2] crypto: tools: Add cryptostat userspace Corentin Labbe
@ 2018-09-28  5:08 ` Herbert Xu
  2 siblings, 0 replies; 18+ messages in thread
From: Herbert Xu @ 2018-09-28  5:08 UTC (permalink / raw)
  To: Corentin Labbe; +Cc: davem, nhorman, linux-crypto, linux-kernel

On Wed, Sep 19, 2018 at 10:10:53AM +0000, Corentin Labbe wrote:
> This patch is a try to implement a generic crypto driver statistics.
> The goal is to have an "ifconfig" for crypto device.
> 
> Some driver tried to implement this via a debugfs interface.
> 
> This serie do it directly in the crypto API and give access to stats
> via the crypto_user(netlink) API.
> Then an userspace tool will collect information via netlink.
> Note that this userspace tool is heavily copied from libkcapi and if
> Stephan Mueller agree, I will made a PR for adding getstat to it unless
> tools/crypto is the good place for it.
> 
> Example of output:
> pkcs1pad(rsa-sun8i-ce,sha1)     Akcipher
>         Encrypt: 0 bytes: 0
>         Decrypt: 0 bytes: 0
>         Sign: 0
>         Verify: 5
>         Errors: 0
> cryptd(__xts-aes-ce)    cipher
>         Encrypt: 0 bytes: 0
>         Decrypt: 0 bytes: 0
>         Errors: 0
> xts-aes-ce      cipher
>         Encrypt: 17 bytes: 4384
>         Decrypt: 17 bytes: 4384
>         Errors: 0
> cryptd(__ctr-aes-ce)    cipher
>         Encrypt: 0 bytes: 0
>         Decrypt: 0 bytes: 0
>         Errors: 0
> ctr-aes-ce      cipher
>         Encrypt: 19 bytes: 5551
>         Decrypt: 19 bytes: 5551
>         Errors: 0
> cryptd(__cbc-aes-ce)    cipher
>         Encrypt: 0 bytes: 0
>         Decrypt: 0 bytes: 0
>         Errors: 0
> cbc-aes-ce      cipher
>         Encrypt: 19 bytes: 3040
>         Decrypt: 19 bytes: 3040
>         Errors: 0
> cryptd(__ecb-aes-ce)    cipher
>         Encrypt: 0 bytes: 0
>         Decrypt: 0 bytes: 0
>         Errors: 0
> ecb-aes-ce      cipher
>         Encrypt: 14 bytes: 2624
>         Decrypt: 14 bytes: 2624
>         Errors: 0
> cbcmac-aes-ce   Hash
>         Hash: 20 bytes: 1244
>         Errors: 0
> xcbc-aes-ce     Hash
>         Hash: 28 bytes: 543
>         Errors: 0
> cmac-aes-ce     Hash
>         Hash: 36 bytes: 1472
>         Errors: 0
> __xts-aes-ce    cipher
>         Encrypt: 17 bytes: 4384
>         Decrypt: 17 bytes: 4384
>         Errors: 0
> ctr-aes-ce      cipher
>         Encrypt: 19 bytes: 5551
>         Decrypt: 19 bytes: 5551
>         Errors: 0
> __ctr-aes-ce    cipher
>         Encrypt: 19 bytes: 5551
>         Decrypt: 19 bytes: 5551
>         Errors: 0
> __cbc-aes-ce    cipher
>         Encrypt: 19 bytes: 3040
>         Decrypt: 19 bytes: 3040
>         Errors: 0
> __ecb-aes-ce    cipher
>         Encrypt: 14 bytes: 2624
>         Decrypt: 14 bytes: 2624
>         Errors: 0
> rsa-sun8i-ce    Akcipher
>         Encrypt: 7 bytes: 232
>         Decrypt: 6 bytes: 1152
>         Sign: 0
>         Verify: 5
>         Errors: 0
> sun8i_ce_rng    RNG
>         Seed: 0
>         Generate: 0 bytes: 0
>         Errors: 0
> ecb(des3_ede-generic)   cipher
>         Encrypt: 24 bytes: 4584
>         Decrypt: 24 bytes: 4584
>         Errors: 0
> ecb-des3-sun8i-ce       cipher
>         Encrypt: 18 bytes: 3072
>         Decrypt: 18 bytes: 3072
>         Errors: 0
> cbc(des3_ede-generic)   cipher
>         Encrypt: 14 bytes: 5104
>         Decrypt: 14 bytes: 5104
>         Errors: 0
> aes-ce  cipher
>         Encrypt: 0 bytes: 0
>         Decrypt: 0 bytes: 0
>         Errors: 0
> des3_ede-generic        cipher
>         Encrypt: 0 bytes: 0
>         Decrypt: 0 bytes: 0
>         Errors: 0
> des-generic     cipher
>         Encrypt: 0 bytes: 0
>         Decrypt: 0 bytes: 0
>         Errors: 0
> aes-arm64       cipher
>         Encrypt: 0 bytes: 0
>         Decrypt: 0 bytes: 0
>         Errors: 0
> crc32c-arm64-ce Hash
>         Hash: 92 bytes: 20649
>         Errors: 0
> cbc-des3-sun8i-ce       cipher
>         Encrypt: 10 bytes: 3488
>         Decrypt: 10 bytes: 3488
>         Errors: 0
> crc32-arm64-ce  Hash
>         Hash: 92 bytes: 20649
>         Errors: 0
> ecb-aes-sun8i-ce        cipher
>         Encrypt: 18 bytes: 3168
>         Decrypt: 18 bytes: 3168
>         Errors: 0
> cbc-aes-sun8i-ce        cipher
>         Encrypt: 24 bytes: 3712
>         Decrypt: 24 bytes: 3712
>         Errors: 0
> sha256-ce       Hash
>         Hash: 26 bytes: 8860
>         Errors: 0
> sha224-ce       Hash
>         Hash: 26 bytes: 8860
>         Errors: 0
> cts(cbc-aes-sun8i-ce)   cipher
>         Encrypt: 24 bytes: 956
>         Decrypt: 24 bytes: 956
>         Errors: 0
> sha224-arm64-neon       Hash
>         Hash: 26 bytes: 8860
>         Errors: 0
> sha256-arm64-neon       Hash
>         Hash: 26 bytes: 8860
>         Errors: 0
> sha224-arm64    Hash
>         Hash: 26 bytes: 8860
>         Errors: 0
> sha256-arm64    Hash
>         Hash: 26 bytes: 8860
>         Errors: 0
> ctr-aes-sun8i-ce        cipher
>         Encrypt: 24 bytes: 6738
>         Decrypt: 24 bytes: 6738
>         Errors: 0
> sha1-ce Hash
>         Hash: 28 bytes: 9191
>         Errors: 0
> ecdh-generic    KPP
>         Setsecret: 4
>         Generate public key: 3
>         Compute_shared_secret: 4
>         Errors: 0
> ghash-generic   Hash
>         Hash: 32 bytes: 4358
>         Errors: 0
> jitterentropy_rng       RNG
>         Seed: 0
>         Generate: 1 bytes: 48
>         Errors: 0
> drbg_nopr_hmac_sha256   RNG
>        Seed: 5
>         Generate: 9 bytes: 1056
>         Errors: 0
> drbg_nopr_hmac_sha512   RNG
>         Seed: 0
>         Generate: 0 bytes: 0
>         Errors: 0
> drbg_nopr_hmac_sha384   RNG
>         Seed: 0
>         Generate: 0 bytes: 0
>         Errors: 0
> drbg_nopr_hmac_sha1     RNG
>         Seed: 0
>         Generate: 0 bytes: 0
>         Errors: 0
> drbg_pr_hmac_sha256     RNG
>         Seed: 4
>         Generate: 8 bytes: 1024
>         Errors: 0
> drbg_pr_hmac_sha512     RNG
>         Seed: 0
>         Generate: 0 bytes: 0
>         Errors: 0
> drbg_pr_hmac_sha384     RNG
>         Seed: 0
>         Generate: 0 bytes: 0
>         Errors: 0
> drbg_pr_hmac_sha1       RNG
>         Seed: 0
>         Generate: 0 bytes: 0
>         Errors: 0
> crct10dif-generic       Hash
>         Hash: 24 bytes: 19893
>         Errors: 0
> crc32c-generic  Hash
>         Hash: 92 bytes: 20649
>         Errors: 0
> aes-generic     cipher
>         Encrypt: 0 bytes: 0
>         Decrypt: 0 bytes: 0
>         Errors: 0
> sha224-generic  Hash
>         Hash: 26 bytes: 8860
>         Errors: 0
> sha256-generic  Hash
>         Hash: 26 bytes: 8860
>         Errors: 0
> sha1-generic    Hash
>         Hash: 28 bytes: 9191
>         Errors: 0
> digest_null-generic     Hash
>         Hash: 0 bytes: 0
>         Errors: 0
> compress_null-generic   Compress
>         Compress: 0 bytes: 0
>         Decompress: 0 bytes: 0
>         Errors: 0
> ecb-cipher_null cipher
>         Encrypt: 0 bytes: 0
>         Decrypt: 0 bytes: 0
>         Errors: 0
> cipher_null-generic     cipher
>         Encrypt: 0 bytes: 0
>         Decrypt: 0 bytes: 0
>         Errors: 0
> rsa-generic     Akcipher
>         Encrypt: 17 bytes: 2832
>         Decrypt: 9 bytes: 1920
>         Sign: 0
>         Verify: 36
>         Errors: 0
> 
> Futur possible additions:
> - Add a "number of needed fallback" statistics.
> - statistics for maximum request size
> 
> Please let me know your opinions about it
> 
> Regards
> 
> Changes since v2:
> - added documentation on new struct crypto_alg members.
> 
> Changes since v1:
> - Do not use anymore CRYPTO_MSG_GETALG and added a dedicated CRYPTO_MSG_GETSTAT
> 
> Changes since RFC:
> - Use cryptouser(netlink) instead of /sys
> - Use atomic_t instead of unsigned long
> - moved stat code into dedicated inline function
> - spelling fixes
> 
> Corentin Labbe (2):
>   crypto: Implement a generic crypto statistics
>   crypto: tools: Add cryptostat userspace
> 
>  crypto/Kconfig                               |  11 +
>  crypto/Makefile                              |   1 +
>  crypto/ahash.c                               |  21 +-
>  crypto/algapi.c                              |   8 +
>  crypto/{crypto_user.c => crypto_user_base.c} |   9 +-
>  crypto/crypto_user_stat.c                    | 463 +++++++++++++++++++++++++++
>  crypto/rng.c                                 |   1 +
>  include/crypto/acompress.h                   |  38 ++-
>  include/crypto/aead.h                        |  51 ++-
>  include/crypto/akcipher.h                    |  76 ++++-
>  include/crypto/hash.h                        |  32 +-
>  include/crypto/internal/cryptouser.h         |   8 +
>  include/crypto/kpp.h                         |  51 ++-
>  include/crypto/rng.h                         |  29 +-
>  include/crypto/skcipher.h                    |  44 ++-
>  include/linux/crypto.h                       | 110 ++++++-
>  include/uapi/linux/cryptouser.h              |  52 +++
>  tools/crypto/getstat.c                       | 294 +++++++++++++++++
>  18 files changed, 1264 insertions(+), 35 deletions(-)
>  rename crypto/{crypto_user.c => crypto_user_base.c} (97%)
>  create mode 100644 crypto/crypto_user_stat.c
>  create mode 100644 include/crypto/internal/cryptouser.h
>  create mode 100644 tools/crypto/getstat.c

All applied.  Thanks.
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 2/2] crypto: tools: Add cryptostat userspace
  2018-09-19 10:10 ` [PATCH v3 2/2] crypto: tools: Add cryptostat userspace Corentin Labbe
@ 2018-09-28 13:13     ` Ard Biesheuvel
  0 siblings, 0 replies; 18+ messages in thread
From: Ard Biesheuvel @ 2018-09-28 13:13 UTC (permalink / raw)
  To: Corentin Labbe
  Cc: David S. Miller, Herbert Xu, nhorman,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE,
	Linux Kernel Mailing List

On 19 September 2018 at 12:10, Corentin Labbe <clabbe@baylibre.com> wrote:
> This patch adds an userspace tool for displaying kernel crypto API
> statistics.
>
> Signed-off-by: Corentin Labbe <clabbe@baylibre.com>

How do I actually build this thing?

> ---
>  tools/crypto/getstat.c | 294 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 294 insertions(+)
>  create mode 100644 tools/crypto/getstat.c
>
> diff --git a/tools/crypto/getstat.c b/tools/crypto/getstat.c
> new file mode 100644
> index 000000000000..24115173a483
> --- /dev/null
> +++ b/tools/crypto/getstat.c
> @@ -0,0 +1,294 @@
> +/* Heavily copied from libkcapi 2015 - 2017, Stephan Mueller <smueller@chronox.de> */
> +#include <errno.h>
> +#include <linux/cryptouser.h>
> +#include <linux/netlink.h>
> +#include <linux/rtnetlink.h>
> +#include <sys/types.h>
> +#include <sys/socket.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <time.h>
> +#include <unistd.h>
> +
> +#define CR_RTA(x)  ((struct rtattr *)(((char *)(x)) + NLMSG_ALIGN(sizeof(struct crypto_user_alg))))
> +
> +static int get_stat(const char *drivername)
> +{
> +       struct {
> +               struct nlmsghdr n;
> +               struct crypto_user_alg cru;
> +       } req;
> +       struct sockaddr_nl nl;
> +       int sd = 0, ret;
> +       socklen_t addr_len;
> +       struct iovec iov;
> +       struct msghdr msg;
> +       char buf[4096];
> +       struct nlmsghdr *res_n = (struct nlmsghdr *)buf;
> +       struct crypto_user_alg *cru_res = NULL;
> +       int res_len = 0;
> +       struct rtattr *tb[CRYPTOCFGA_MAX + 1];
> +       struct rtattr *rta;
> +       struct nlmsgerr *errmsg;
> +
> +       memset(&req, 0, sizeof(req));
> +       memset(&buf, 0, sizeof(buf));
> +       memset(&msg, 0, sizeof(msg));
> +
> +       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.cru));
> +       req.n.nlmsg_flags = NLM_F_REQUEST;
> +       req.n.nlmsg_type = CRYPTO_MSG_GETSTAT;
> +       req.n.nlmsg_seq = time(NULL);
> +
> +       strncpy(req.cru.cru_driver_name, drivername, strlen(drivername));
> +
> +       sd =  socket(AF_NETLINK, SOCK_RAW, NETLINK_CRYPTO);
> +       if (sd < 0) {
> +               fprintf(stderr, "Netlink error: cannot open netlink socket");
> +               return -errno;
> +       }
> +       memset(&nl, 0, sizeof(nl));
> +       nl.nl_family = AF_NETLINK;
> +       if (bind(sd, (struct sockaddr *)&nl, sizeof(nl)) < 0) {
> +               ret = -errno;
> +               fprintf(stderr, "Netlink error: cannot bind netlink socket");
> +               goto out;
> +       }
> +
> +       /* sanity check that netlink socket was successfully opened */
> +       addr_len = sizeof(nl);
> +       if (getsockname(sd, (struct sockaddr *)&nl, &addr_len) < 0) {
> +               ret = -errno;
> +               printf("Netlink error: cannot getsockname");
> +               goto out;
> +       }
> +       if (addr_len != sizeof(nl)) {
> +               ret = -errno;
> +               printf("Netlink error: wrong address length %d", addr_len);
> +               goto out;
> +       }
> +       if (nl.nl_family != AF_NETLINK) {
> +               ret = -errno;
> +               printf("Netlink error: wrong address family %d",
> +                               nl.nl_family);
> +               goto out;
> +       }
> +
> +       memset(&nl, 0, sizeof(nl));
> +       nl.nl_family = AF_NETLINK;
> +       iov.iov_base = (void *)&req.n;
> +       iov.iov_len = req.n.nlmsg_len;
> +       msg.msg_name = &nl;
> +       msg.msg_namelen = sizeof(nl);
> +       msg.msg_iov = &iov;
> +       msg.msg_iovlen = 1;
> +       if (sendmsg(sd, &msg, 0) < 0) {
> +               ret = -errno;
> +               printf("Netlink error: sendmsg failed");
> +               goto out;
> +       }
> +       memset(buf, 0, sizeof(buf));
> +       iov.iov_base = buf;
> +       while (1) {
> +               iov.iov_len = sizeof(buf);
> +               ret = recvmsg(sd, &msg, 0);
> +               if (ret < 0) {
> +                       if (errno == EINTR || errno == EAGAIN)
> +                               continue;
> +                       ret = -errno;
> +                       printf("Netlink error: netlink receive error");
> +                       goto out;
> +               }
> +               if (ret == 0) {
> +                       ret = -errno;
> +                       printf("Netlink error: no data");
> +                       goto out;
> +               }
> +               if (ret > sizeof(buf)) {
> +                       ret = -errno;
> +                       printf("Netlink error: received too much data");
> +                       goto out;
> +               }
> +               break;
> +       }
> +
> +       ret = -EFAULT;
> +       res_len = res_n->nlmsg_len;
> +       if (res_n->nlmsg_type == NLMSG_ERROR) {
> +               errmsg = NLMSG_DATA(res_n);
> +               fprintf(stderr, "Fail with %d\n", errmsg->error);
> +               ret = errmsg->error;
> +               goto out;
> +       }
> +
> +       if (res_n->nlmsg_type == CRYPTO_MSG_GETSTAT) {
> +               cru_res = NLMSG_DATA(res_n);
> +               res_len -= NLMSG_SPACE(sizeof(*cru_res));
> +       }
> +       if (res_len < 0) {
> +               printf("Netlink error: nlmsg len %d\n", res_len);
> +               goto out;
> +       }
> +
> +       if (!cru_res) {
> +               ret = -EFAULT;
> +               printf("Netlink error: no cru_res\n");
> +               goto out;
> +       }
> +
> +       rta = CR_RTA(cru_res);
> +       memset(tb, 0, sizeof(struct rtattr *) * (CRYPTOCFGA_MAX + 1));
> +       while (RTA_OK(rta, res_len)) {
> +               if ((rta->rta_type <= CRYPTOCFGA_MAX) && (!tb[rta->rta_type]))
> +                       tb[rta->rta_type] = rta;
> +               rta = RTA_NEXT(rta, res_len);
> +       }
> +       if (res_len) {
> +               printf("Netlink error: unprocessed data %d",
> +                               res_len);
> +               goto out;
> +       }
> +
> +       if (tb[CRYPTOCFGA_STAT_HASH]) {
> +               struct rtattr *rta = tb[CRYPTOCFGA_STAT_HASH];
> +               struct crypto_stat *rhash =
> +                       (struct crypto_stat *)RTA_DATA(rta);
> +               printf("%s\tHash\n\tHash: %u bytes: %llu\n\tErrors: %u\n",
> +                       drivername,
> +                       rhash->stat_hash_cnt, rhash->stat_hash_tlen,
> +                       rhash->stat_hash_err_cnt);
> +       } else if (tb[CRYPTOCFGA_STAT_COMPRESS]) {
> +               struct rtattr *rta = tb[CRYPTOCFGA_STAT_COMPRESS];
> +               struct crypto_stat *rblk =
> +                       (struct crypto_stat *)RTA_DATA(rta);
> +               printf("%s\tCompress\n\tCompress: %u bytes: %llu\n\tDecompress: %u bytes: %llu\n\tErrors: %u\n",
> +                       drivername,
> +                       rblk->stat_compress_cnt, rblk->stat_compress_tlen,
> +                       rblk->stat_decompress_cnt, rblk->stat_decompress_tlen,
> +                       rblk->stat_compress_err_cnt);
> +       } else if (tb[CRYPTOCFGA_STAT_ACOMP]) {
> +               struct rtattr *rta = tb[CRYPTOCFGA_STAT_ACOMP];
> +               struct crypto_stat *rcomp =
> +                       (struct crypto_stat *)RTA_DATA(rta);
> +               printf("%s\tACompress\n\tCompress: %u bytes: %llu\n\tDecompress: %u bytes: %llu\n\tErrors: %u\n",
> +                       drivername,
> +                       rcomp->stat_compress_cnt, rcomp->stat_compress_tlen,
> +                       rcomp->stat_decompress_cnt, rcomp->stat_decompress_tlen,
> +                       rcomp->stat_compress_err_cnt);
> +       } else if (tb[CRYPTOCFGA_STAT_AEAD]) {
> +               struct rtattr *rta = tb[CRYPTOCFGA_STAT_AEAD];
> +               struct crypto_stat *raead =
> +                       (struct crypto_stat *)RTA_DATA(rta);
> +               printf("%s\tAEAD\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tErrors: %u\n",
> +                       drivername,
> +                       raead->stat_encrypt_cnt, raead->stat_encrypt_tlen,
> +                       raead->stat_decrypt_cnt, raead->stat_decrypt_tlen,
> +                       raead->stat_aead_err_cnt);
> +       } else if (tb[CRYPTOCFGA_STAT_BLKCIPHER]) {
> +               struct rtattr *rta = tb[CRYPTOCFGA_STAT_BLKCIPHER];
> +               struct crypto_stat *rblk =
> +                       (struct crypto_stat *)RTA_DATA(rta);
> +               printf("%s\tCipher\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tErrors: %u\n",
> +                       drivername,
> +                       rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen,
> +                       rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen,
> +                       rblk->stat_cipher_err_cnt);
> +       } else if (tb[CRYPTOCFGA_STAT_AKCIPHER]) {
> +               struct rtattr *rta = tb[CRYPTOCFGA_STAT_AKCIPHER];
> +               struct crypto_stat *rblk =
> +                       (struct crypto_stat *)RTA_DATA(rta);
> +               printf("%s\tAkcipher\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tSign: %u\n\tVerify: %u\n\tErrors: %u\n",
> +                       drivername,
> +                       rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen,
> +                       rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen,
> +                       rblk->stat_sign_cnt, rblk->stat_verify_cnt,
> +                       rblk->stat_akcipher_err_cnt);
> +       } else if (tb[CRYPTOCFGA_STAT_CIPHER]) {
> +               struct rtattr *rta = tb[CRYPTOCFGA_STAT_CIPHER];
> +               struct crypto_stat *rblk =
> +                       (struct crypto_stat *)RTA_DATA(rta);
> +               printf("%s\tcipher\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tErrors: %u\n",
> +                       drivername,
> +                       rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen,
> +                       rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen,
> +                       rblk->stat_cipher_err_cnt);
> +       } else if (tb[CRYPTOCFGA_STAT_RNG]) {
> +               struct rtattr *rta = tb[CRYPTOCFGA_STAT_RNG];
> +               struct crypto_stat *rrng =
> +                       (struct crypto_stat *)RTA_DATA(rta);
> +               printf("%s\tRNG\n\tSeed: %u\n\tGenerate: %u bytes: %llu\n\tErrors: %u\n",
> +                       drivername,
> +                       rrng->stat_seed_cnt,
> +                       rrng->stat_generate_cnt, rrng->stat_generate_tlen,
> +                       rrng->stat_rng_err_cnt);
> +       } else if (tb[CRYPTOCFGA_STAT_KPP]) {
> +               struct rtattr *rta = tb[CRYPTOCFGA_STAT_KPP];
> +               struct crypto_stat *rkpp =
> +                       (struct crypto_stat *)RTA_DATA(rta);
> +               printf("%s\tKPP\n\tSetsecret: %u\n\tGenerate public key: %u\n\tCompute_shared_secret: %u\n\tErrors: %u\n",
> +                       drivername,
> +                       rkpp->stat_setsecret_cnt,
> +                       rkpp->stat_generate_public_key_cnt,
> +                       rkpp->stat_compute_shared_secret_cnt,
> +                       rkpp->stat_kpp_err_cnt);
> +       } else {
> +               fprintf(stderr, "%s is of an unknown algorithm\n", drivername);
> +       }
> +       ret = 0;
> +out:
> +       close(sd);
> +       return ret;
> +}
> +
> +int main(int argc, const char *argv[])
> +{
> +       char buf[4096];
> +       FILE *procfd;
> +       int i, lastspace;
> +       int ret;
> +
> +       procfd = fopen("/proc/crypto", "r");
> +       if (!procfd) {
> +               ret = errno;
> +               fprintf(stderr, "Cannot open /proc/crypto %s\n", strerror(errno));
> +               return ret;
> +       }
> +       if (argc > 1) {
> +               if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
> +                       printf("Usage: %s [-h|--help] display this help\n", argv[0]);
> +                       printf("Usage: %s display all crypto statistics\n", argv[0]);
> +                       printf("Usage: %s drivername1 drivername2 ... = display crypto statistics about drivername1 ...\n", argv[0]);
> +                       return 0;
> +               }
> +               for (i = 1; i < argc; i++) {
> +                       ret = get_stat(argv[i]);
> +                       if (ret) {
> +                               fprintf(stderr, "Failed with %s\n", strerror(-ret));
> +                               return ret;
> +                       }
> +               }
> +               return 0;
> +       }
> +
> +       while (fgets(buf, sizeof(buf), procfd)) {
> +               if (!strncmp(buf, "driver", 6)) {
> +                       lastspace = 0;
> +                       i = 0;
> +                       while (i < strlen(buf)) {
> +                               i++;
> +                               if (buf[i] == ' ')
> +                                       lastspace = i;
> +                       }
> +                       buf[strlen(buf) - 1] = '\0';
> +                       ret = get_stat(buf + lastspace + 1);
> +                       if (ret) {
> +                               fprintf(stderr, "Failed with %s\n", strerror(-ret));
> +                               goto out;
> +                       }
> +               }
> +       }
> +out:
> +       fclose(procfd);
> +       return ret;
> +}
> --
> 2.16.4
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 2/2] crypto: tools: Add cryptostat userspace
@ 2018-09-28 13:13     ` Ard Biesheuvel
  0 siblings, 0 replies; 18+ messages in thread
From: Ard Biesheuvel @ 2018-09-28 13:13 UTC (permalink / raw)
  To: Corentin Labbe
  Cc: David S. Miller, Herbert Xu, nhorman,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE,
	Linux Kernel Mailing List

On 19 September 2018 at 12:10, Corentin Labbe <clabbe@baylibre.com> wrote:
> This patch adds an userspace tool for displaying kernel crypto API
> statistics.
>
> Signed-off-by: Corentin Labbe <clabbe@baylibre.com>

How do I actually build this thing?

> ---
>  tools/crypto/getstat.c | 294 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 294 insertions(+)
>  create mode 100644 tools/crypto/getstat.c
>
> diff --git a/tools/crypto/getstat.c b/tools/crypto/getstat.c
> new file mode 100644
> index 000000000000..24115173a483
> --- /dev/null
> +++ b/tools/crypto/getstat.c
> @@ -0,0 +1,294 @@
> +/* Heavily copied from libkcapi 2015 - 2017, Stephan Mueller <smueller@chronox.de> */
> +#include <errno.h>
> +#include <linux/cryptouser.h>
> +#include <linux/netlink.h>
> +#include <linux/rtnetlink.h>
> +#include <sys/types.h>
> +#include <sys/socket.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <time.h>
> +#include <unistd.h>
> +
> +#define CR_RTA(x)  ((struct rtattr *)(((char *)(x)) + NLMSG_ALIGN(sizeof(struct crypto_user_alg))))
> +
> +static int get_stat(const char *drivername)
> +{
> +       struct {
> +               struct nlmsghdr n;
> +               struct crypto_user_alg cru;
> +       } req;
> +       struct sockaddr_nl nl;
> +       int sd = 0, ret;
> +       socklen_t addr_len;
> +       struct iovec iov;
> +       struct msghdr msg;
> +       char buf[4096];
> +       struct nlmsghdr *res_n = (struct nlmsghdr *)buf;
> +       struct crypto_user_alg *cru_res = NULL;
> +       int res_len = 0;
> +       struct rtattr *tb[CRYPTOCFGA_MAX + 1];
> +       struct rtattr *rta;
> +       struct nlmsgerr *errmsg;
> +
> +       memset(&req, 0, sizeof(req));
> +       memset(&buf, 0, sizeof(buf));
> +       memset(&msg, 0, sizeof(msg));
> +
> +       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.cru));
> +       req.n.nlmsg_flags = NLM_F_REQUEST;
> +       req.n.nlmsg_type = CRYPTO_MSG_GETSTAT;
> +       req.n.nlmsg_seq = time(NULL);
> +
> +       strncpy(req.cru.cru_driver_name, drivername, strlen(drivername));
> +
> +       sd =  socket(AF_NETLINK, SOCK_RAW, NETLINK_CRYPTO);
> +       if (sd < 0) {
> +               fprintf(stderr, "Netlink error: cannot open netlink socket");
> +               return -errno;
> +       }
> +       memset(&nl, 0, sizeof(nl));
> +       nl.nl_family = AF_NETLINK;
> +       if (bind(sd, (struct sockaddr *)&nl, sizeof(nl)) < 0) {
> +               ret = -errno;
> +               fprintf(stderr, "Netlink error: cannot bind netlink socket");
> +               goto out;
> +       }
> +
> +       /* sanity check that netlink socket was successfully opened */
> +       addr_len = sizeof(nl);
> +       if (getsockname(sd, (struct sockaddr *)&nl, &addr_len) < 0) {
> +               ret = -errno;
> +               printf("Netlink error: cannot getsockname");
> +               goto out;
> +       }
> +       if (addr_len != sizeof(nl)) {
> +               ret = -errno;
> +               printf("Netlink error: wrong address length %d", addr_len);
> +               goto out;
> +       }
> +       if (nl.nl_family != AF_NETLINK) {
> +               ret = -errno;
> +               printf("Netlink error: wrong address family %d",
> +                               nl.nl_family);
> +               goto out;
> +       }
> +
> +       memset(&nl, 0, sizeof(nl));
> +       nl.nl_family = AF_NETLINK;
> +       iov.iov_base = (void *)&req.n;
> +       iov.iov_len = req.n.nlmsg_len;
> +       msg.msg_name = &nl;
> +       msg.msg_namelen = sizeof(nl);
> +       msg.msg_iov = &iov;
> +       msg.msg_iovlen = 1;
> +       if (sendmsg(sd, &msg, 0) < 0) {
> +               ret = -errno;
> +               printf("Netlink error: sendmsg failed");
> +               goto out;
> +       }
> +       memset(buf, 0, sizeof(buf));
> +       iov.iov_base = buf;
> +       while (1) {
> +               iov.iov_len = sizeof(buf);
> +               ret = recvmsg(sd, &msg, 0);
> +               if (ret < 0) {
> +                       if (errno == EINTR || errno == EAGAIN)
> +                               continue;
> +                       ret = -errno;
> +                       printf("Netlink error: netlink receive error");
> +                       goto out;
> +               }
> +               if (ret == 0) {
> +                       ret = -errno;
> +                       printf("Netlink error: no data");
> +                       goto out;
> +               }
> +               if (ret > sizeof(buf)) {
> +                       ret = -errno;
> +                       printf("Netlink error: received too much data");
> +                       goto out;
> +               }
> +               break;
> +       }
> +
> +       ret = -EFAULT;
> +       res_len = res_n->nlmsg_len;
> +       if (res_n->nlmsg_type == NLMSG_ERROR) {
> +               errmsg = NLMSG_DATA(res_n);
> +               fprintf(stderr, "Fail with %d\n", errmsg->error);
> +               ret = errmsg->error;
> +               goto out;
> +       }
> +
> +       if (res_n->nlmsg_type == CRYPTO_MSG_GETSTAT) {
> +               cru_res = NLMSG_DATA(res_n);
> +               res_len -= NLMSG_SPACE(sizeof(*cru_res));
> +       }
> +       if (res_len < 0) {
> +               printf("Netlink error: nlmsg len %d\n", res_len);
> +               goto out;
> +       }
> +
> +       if (!cru_res) {
> +               ret = -EFAULT;
> +               printf("Netlink error: no cru_res\n");
> +               goto out;
> +       }
> +
> +       rta = CR_RTA(cru_res);
> +       memset(tb, 0, sizeof(struct rtattr *) * (CRYPTOCFGA_MAX + 1));
> +       while (RTA_OK(rta, res_len)) {
> +               if ((rta->rta_type <= CRYPTOCFGA_MAX) && (!tb[rta->rta_type]))
> +                       tb[rta->rta_type] = rta;
> +               rta = RTA_NEXT(rta, res_len);
> +       }
> +       if (res_len) {
> +               printf("Netlink error: unprocessed data %d",
> +                               res_len);
> +               goto out;
> +       }
> +
> +       if (tb[CRYPTOCFGA_STAT_HASH]) {
> +               struct rtattr *rta = tb[CRYPTOCFGA_STAT_HASH];
> +               struct crypto_stat *rhash =
> +                       (struct crypto_stat *)RTA_DATA(rta);
> +               printf("%s\tHash\n\tHash: %u bytes: %llu\n\tErrors: %u\n",
> +                       drivername,
> +                       rhash->stat_hash_cnt, rhash->stat_hash_tlen,
> +                       rhash->stat_hash_err_cnt);
> +       } else if (tb[CRYPTOCFGA_STAT_COMPRESS]) {
> +               struct rtattr *rta = tb[CRYPTOCFGA_STAT_COMPRESS];
> +               struct crypto_stat *rblk =
> +                       (struct crypto_stat *)RTA_DATA(rta);
> +               printf("%s\tCompress\n\tCompress: %u bytes: %llu\n\tDecompress: %u bytes: %llu\n\tErrors: %u\n",
> +                       drivername,
> +                       rblk->stat_compress_cnt, rblk->stat_compress_tlen,
> +                       rblk->stat_decompress_cnt, rblk->stat_decompress_tlen,
> +                       rblk->stat_compress_err_cnt);
> +       } else if (tb[CRYPTOCFGA_STAT_ACOMP]) {
> +               struct rtattr *rta = tb[CRYPTOCFGA_STAT_ACOMP];
> +               struct crypto_stat *rcomp =
> +                       (struct crypto_stat *)RTA_DATA(rta);
> +               printf("%s\tACompress\n\tCompress: %u bytes: %llu\n\tDecompress: %u bytes: %llu\n\tErrors: %u\n",
> +                       drivername,
> +                       rcomp->stat_compress_cnt, rcomp->stat_compress_tlen,
> +                       rcomp->stat_decompress_cnt, rcomp->stat_decompress_tlen,
> +                       rcomp->stat_compress_err_cnt);
> +       } else if (tb[CRYPTOCFGA_STAT_AEAD]) {
> +               struct rtattr *rta = tb[CRYPTOCFGA_STAT_AEAD];
> +               struct crypto_stat *raead =
> +                       (struct crypto_stat *)RTA_DATA(rta);
> +               printf("%s\tAEAD\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tErrors: %u\n",
> +                       drivername,
> +                       raead->stat_encrypt_cnt, raead->stat_encrypt_tlen,
> +                       raead->stat_decrypt_cnt, raead->stat_decrypt_tlen,
> +                       raead->stat_aead_err_cnt);
> +       } else if (tb[CRYPTOCFGA_STAT_BLKCIPHER]) {
> +               struct rtattr *rta = tb[CRYPTOCFGA_STAT_BLKCIPHER];
> +               struct crypto_stat *rblk =
> +                       (struct crypto_stat *)RTA_DATA(rta);
> +               printf("%s\tCipher\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tErrors: %u\n",
> +                       drivername,
> +                       rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen,
> +                       rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen,
> +                       rblk->stat_cipher_err_cnt);
> +       } else if (tb[CRYPTOCFGA_STAT_AKCIPHER]) {
> +               struct rtattr *rta = tb[CRYPTOCFGA_STAT_AKCIPHER];
> +               struct crypto_stat *rblk =
> +                       (struct crypto_stat *)RTA_DATA(rta);
> +               printf("%s\tAkcipher\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tSign: %u\n\tVerify: %u\n\tErrors: %u\n",
> +                       drivername,
> +                       rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen,
> +                       rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen,
> +                       rblk->stat_sign_cnt, rblk->stat_verify_cnt,
> +                       rblk->stat_akcipher_err_cnt);
> +       } else if (tb[CRYPTOCFGA_STAT_CIPHER]) {
> +               struct rtattr *rta = tb[CRYPTOCFGA_STAT_CIPHER];
> +               struct crypto_stat *rblk =
> +                       (struct crypto_stat *)RTA_DATA(rta);
> +               printf("%s\tcipher\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tErrors: %u\n",
> +                       drivername,
> +                       rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen,
> +                       rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen,
> +                       rblk->stat_cipher_err_cnt);
> +       } else if (tb[CRYPTOCFGA_STAT_RNG]) {
> +               struct rtattr *rta = tb[CRYPTOCFGA_STAT_RNG];
> +               struct crypto_stat *rrng =
> +                       (struct crypto_stat *)RTA_DATA(rta);
> +               printf("%s\tRNG\n\tSeed: %u\n\tGenerate: %u bytes: %llu\n\tErrors: %u\n",
> +                       drivername,
> +                       rrng->stat_seed_cnt,
> +                       rrng->stat_generate_cnt, rrng->stat_generate_tlen,
> +                       rrng->stat_rng_err_cnt);
> +       } else if (tb[CRYPTOCFGA_STAT_KPP]) {
> +               struct rtattr *rta = tb[CRYPTOCFGA_STAT_KPP];
> +               struct crypto_stat *rkpp =
> +                       (struct crypto_stat *)RTA_DATA(rta);
> +               printf("%s\tKPP\n\tSetsecret: %u\n\tGenerate public key: %u\n\tCompute_shared_secret: %u\n\tErrors: %u\n",
> +                       drivername,
> +                       rkpp->stat_setsecret_cnt,
> +                       rkpp->stat_generate_public_key_cnt,
> +                       rkpp->stat_compute_shared_secret_cnt,
> +                       rkpp->stat_kpp_err_cnt);
> +       } else {
> +               fprintf(stderr, "%s is of an unknown algorithm\n", drivername);
> +       }
> +       ret = 0;
> +out:
> +       close(sd);
> +       return ret;
> +}
> +
> +int main(int argc, const char *argv[])
> +{
> +       char buf[4096];
> +       FILE *procfd;
> +       int i, lastspace;
> +       int ret;
> +
> +       procfd = fopen("/proc/crypto", "r");
> +       if (!procfd) {
> +               ret = errno;
> +               fprintf(stderr, "Cannot open /proc/crypto %s\n", strerror(errno));
> +               return ret;
> +       }
> +       if (argc > 1) {
> +               if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
> +                       printf("Usage: %s [-h|--help] display this help\n", argv[0]);
> +                       printf("Usage: %s display all crypto statistics\n", argv[0]);
> +                       printf("Usage: %s drivername1 drivername2 ... = display crypto statistics about drivername1 ...\n", argv[0]);
> +                       return 0;
> +               }
> +               for (i = 1; i < argc; i++) {
> +                       ret = get_stat(argv[i]);
> +                       if (ret) {
> +                               fprintf(stderr, "Failed with %s\n", strerror(-ret));
> +                               return ret;
> +                       }
> +               }
> +               return 0;
> +       }
> +
> +       while (fgets(buf, sizeof(buf), procfd)) {
> +               if (!strncmp(buf, "driver", 6)) {
> +                       lastspace = 0;
> +                       i = 0;
> +                       while (i < strlen(buf)) {
> +                               i++;
> +                               if (buf[i] == ' ')
> +                                       lastspace = i;
> +                       }
> +                       buf[strlen(buf) - 1] = '\0';
> +                       ret = get_stat(buf + lastspace + 1);
> +                       if (ret) {
> +                               fprintf(stderr, "Failed with %s\n", strerror(-ret));
> +                               goto out;
> +                       }
> +               }
> +       }
> +out:
> +       fclose(procfd);
> +       return ret;
> +}
> --
> 2.16.4
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 2/2] crypto: tools: Add cryptostat userspace
  2018-09-28 13:13     ` Ard Biesheuvel
@ 2018-09-28 17:03       ` Ard Biesheuvel
  -1 siblings, 0 replies; 18+ messages in thread
From: Ard Biesheuvel @ 2018-09-28 17:03 UTC (permalink / raw)
  To: Corentin Labbe
  Cc: David S. Miller, Herbert Xu, nhorman,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE,
	Linux Kernel Mailing List

On 28 September 2018 at 15:13, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> On 19 September 2018 at 12:10, Corentin Labbe <clabbe@baylibre.com> wrote:
>> This patch adds an userspace tool for displaying kernel crypto API
>> statistics.
>>
>> Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
>
> How do I actually build this thing?
>

Never mind.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 2/2] crypto: tools: Add cryptostat userspace
@ 2018-09-28 17:03       ` Ard Biesheuvel
  0 siblings, 0 replies; 18+ messages in thread
From: Ard Biesheuvel @ 2018-09-28 17:03 UTC (permalink / raw)
  To: Corentin Labbe
  Cc: David S. Miller, Herbert Xu, nhorman,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE,
	Linux Kernel Mailing List

On 28 September 2018 at 15:13, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> On 19 September 2018 at 12:10, Corentin Labbe <clabbe@baylibre.com> wrote:
>> This patch adds an userspace tool for displaying kernel crypto API
>> statistics.
>>
>> Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
>
> How do I actually build this thing?
>

Never mind.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 2/2] crypto: tools: Add cryptostat userspace
  2018-09-28 17:03       ` Ard Biesheuvel
@ 2018-10-01  7:20         ` LABBE Corentin
  -1 siblings, 0 replies; 18+ messages in thread
From: LABBE Corentin @ 2018-10-01  7:20 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: David S. Miller, Herbert Xu, nhorman,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE,
	Linux Kernel Mailing List

On Fri, Sep 28, 2018 at 07:03:11PM +0200, Ard Biesheuvel wrote:
> On 28 September 2018 at 15:13, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> > On 19 September 2018 at 12:10, Corentin Labbe <clabbe@baylibre.com> wrote:
> >> This patch adds an userspace tool for displaying kernel crypto API
> >> statistics.
> >>
> >> Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
> >
> > How do I actually build this thing?
> >
> 
> Never mind.

Nope you are are right, this patchset clearly lack documentation.

I will send a subsequent patch with it.

Furthermore, since you seems to use cryptostat, what's your usage/opinion about it and what statistic it miss.

Regards

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 2/2] crypto: tools: Add cryptostat userspace
@ 2018-10-01  7:20         ` LABBE Corentin
  0 siblings, 0 replies; 18+ messages in thread
From: LABBE Corentin @ 2018-10-01  7:20 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: David S. Miller, Herbert Xu, nhorman,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE,
	Linux Kernel Mailing List

On Fri, Sep 28, 2018 at 07:03:11PM +0200, Ard Biesheuvel wrote:
> On 28 September 2018 at 15:13, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> > On 19 September 2018 at 12:10, Corentin Labbe <clabbe@baylibre.com> wrote:
> >> This patch adds an userspace tool for displaying kernel crypto API
> >> statistics.
> >>
> >> Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
> >
> > How do I actually build this thing?
> >
> 
> Never mind.

Nope you are are right, this patchset clearly lack documentation.

I will send a subsequent patch with it.

Furthermore, since you seems to use cryptostat, what's your usage/opinion about it and what statistic it miss.

Regards

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 2/2] crypto: tools: Add cryptostat userspace
  2018-10-01  7:20         ` LABBE Corentin
@ 2018-10-01  8:40           ` Ard Biesheuvel
  -1 siblings, 0 replies; 18+ messages in thread
From: Ard Biesheuvel @ 2018-10-01  8:40 UTC (permalink / raw)
  To: LABBE Corentin
  Cc: David S. Miller, Herbert Xu, nhorman,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE,
	Linux Kernel Mailing List

On 1 October 2018 at 09:20, LABBE Corentin <clabbe@baylibre.com> wrote:
> On Fri, Sep 28, 2018 at 07:03:11PM +0200, Ard Biesheuvel wrote:
>> On 28 September 2018 at 15:13, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
>> > On 19 September 2018 at 12:10, Corentin Labbe <clabbe@baylibre.com> wrote:
>> >> This patch adds an userspace tool for displaying kernel crypto API
>> >> statistics.
>> >>
>> >> Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
>> >
>> > How do I actually build this thing?
>> >
>>
>> Never mind.
>
> Nope you are are right, this patchset clearly lack documentation.
>
> I will send a subsequent patch with it.
>
> Furthermore, since you seems to use cryptostat, what's your usage/opinion about it and what statistic it miss.
>

To be honest, I mainly used it to check whether a certain cipher is
being used at all or not, i.e., to check whether the my mac80211
interface is really using the arc4 and ccmp ciphers it allocates, or
whether they are simply there as a fallback.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 2/2] crypto: tools: Add cryptostat userspace
@ 2018-10-01  8:40           ` Ard Biesheuvel
  0 siblings, 0 replies; 18+ messages in thread
From: Ard Biesheuvel @ 2018-10-01  8:40 UTC (permalink / raw)
  To: LABBE Corentin
  Cc: David S. Miller, Herbert Xu, nhorman,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE,
	Linux Kernel Mailing List

On 1 October 2018 at 09:20, LABBE Corentin <clabbe@baylibre.com> wrote:
> On Fri, Sep 28, 2018 at 07:03:11PM +0200, Ard Biesheuvel wrote:
>> On 28 September 2018 at 15:13, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
>> > On 19 September 2018 at 12:10, Corentin Labbe <clabbe@baylibre.com> wrote:
>> >> This patch adds an userspace tool for displaying kernel crypto API
>> >> statistics.
>> >>
>> >> Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
>> >
>> > How do I actually build this thing?
>> >
>>
>> Never mind.
>
> Nope you are are right, this patchset clearly lack documentation.
>
> I will send a subsequent patch with it.
>
> Furthermore, since you seems to use cryptostat, what's your usage/opinion about it and what statistic it miss.
>

To be honest, I mainly used it to check whether a certain cipher is
being used at all or not, i.e., to check whether the my mac80211
interface is really using the arc4 and ccmp ciphers it allocates, or
whether they are simply there as a fallback.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 1/2] crypto: Implement a generic crypto statistics
  2018-09-19 10:10 ` [PATCH v3 1/2] " Corentin Labbe
@ 2018-11-03 22:19   ` Eric Biggers
  2018-11-04  9:11     ` LABBE Corentin
  2018-11-03 22:52   ` Eric Biggers
  2018-12-06  0:04   ` Eric Biggers
  2 siblings, 1 reply; 18+ messages in thread
From: Eric Biggers @ 2018-11-03 22:19 UTC (permalink / raw)
  To: Corentin Labbe; +Cc: davem, herbert, nhorman, linux-crypto, linux-kernel

Hi Corentin,

On Wed, Sep 19, 2018 at 10:10:54AM +0000, Corentin Labbe wrote:
> This patch implement a generic way to get statistics about all crypto
> usages.
> 
> Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
> ---
>  crypto/Kconfig                               |  11 +
>  crypto/Makefile                              |   1 +
>  crypto/ahash.c                               |  21 +-
>  crypto/algapi.c                              |   8 +
>  crypto/{crypto_user.c => crypto_user_base.c} |   9 +-
>  crypto/crypto_user_stat.c                    | 463 +++++++++++++++++++++++++++
>  crypto/rng.c                                 |   1 +
>  include/crypto/acompress.h                   |  38 ++-
>  include/crypto/aead.h                        |  51 ++-
>  include/crypto/akcipher.h                    |  76 ++++-
>  include/crypto/hash.h                        |  32 +-
>  include/crypto/internal/cryptouser.h         |   8 +
>  include/crypto/kpp.h                         |  51 ++-
>  include/crypto/rng.h                         |  29 +-
>  include/crypto/skcipher.h                    |  44 ++-
>  include/linux/crypto.h                       | 110 ++++++-
>  include/uapi/linux/cryptouser.h              |  52 +++
>  17 files changed, 970 insertions(+), 35 deletions(-)
>  rename crypto/{crypto_user.c => crypto_user_base.c} (97%)
>  create mode 100644 crypto/crypto_user_stat.c
>  create mode 100644 include/crypto/internal/cryptouser.h
> 
> diff --git a/crypto/Kconfig b/crypto/Kconfig
> index 90f2811fac5f..4ef95b0b25a3 100644
> --- a/crypto/Kconfig
> +++ b/crypto/Kconfig
> @@ -1799,6 +1799,17 @@ config CRYPTO_USER_API_AEAD
>  	  This option enables the user-spaces interface for AEAD
>  	  cipher algorithms.
>  
> +config CRYPTO_STATS
> +	bool "Crypto usage statistics for User-space"
> +	help
> +	  This option enables the gathering of crypto stats.
> +	  This will collect:
> +	  - encrypt/decrypt size and numbers of symmeric operations
> +	  - compress/decompress size and numbers of compress operations
> +	  - size and numbers of hash operations
> +	  - encrypt/decrypt/sign/verify numbers for asymmetric operations
> +	  - generate/seed numbers for rng operations
> +
>  config CRYPTO_HASH_INFO
>  	bool
>  
> diff --git a/crypto/Makefile b/crypto/Makefile
> index d719843f8b6e..ff5c2bbda04a 100644
> --- a/crypto/Makefile
> +++ b/crypto/Makefile
> @@ -54,6 +54,7 @@ cryptomgr-y := algboss.o testmgr.o
>  
>  obj-$(CONFIG_CRYPTO_MANAGER2) += cryptomgr.o
>  obj-$(CONFIG_CRYPTO_USER) += crypto_user.o
> +crypto_user-y := crypto_user_base.o crypto_user_stat.o
>  obj-$(CONFIG_CRYPTO_CMAC) += cmac.o
>  obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
>  obj-$(CONFIG_CRYPTO_VMAC) += vmac.o

Why is crypto_user_stat.c always being compiled when CONFIG_CRYPTO_USER is
enabled, even when CONFIG_CRYPTO_STATS is not?

When CONFIG_CRYPTO_STATS is disabled, all the crypto stat stuff should be
stubbed out so that crypto_user_stat.c doesn't need to be compiled.

[...]
> diff --git a/include/linux/crypto.h b/include/linux/crypto.h
> index e8839d3a7559..3634ad6fe202 100644
> --- a/include/linux/crypto.h
> +++ b/include/linux/crypto.h
> @@ -454,6 +454,33 @@ struct compress_alg {
>   * @cra_refcnt: internally used
>   * @cra_destroy: internally used
>   *
> + * All following statistics are for this crypto_alg
> + * @encrypt_cnt:	number of encrypt requests
> + * @decrypt_cnt:	number of decrypt requests
> + * @compress_cnt:	number of compress requests
> + * @decompress_cnt:	number of decompress requests
> + * @generate_cnt:	number of RNG generate requests
> + * @seed_cnt:		number of times the rng was seeded
> + * @hash_cnt:		number of hash requests
> + * @sign_cnt:		number of sign requests
> + * @setsecret_cnt:	number of setsecrey operation
> + * @generate_public_key_cnt:	number of generate_public_key operation
> + * @verify_cnt:			number of verify operation
> + * @compute_shared_secret_cnt:	number of compute_shared_secret operation
> + * @encrypt_tlen:	total data size handled by encrypt requests
> + * @decrypt_tlen:	total data size handled by decrypt requests
> + * @compress_tlen:	total data size handled by compress requests
> + * @decompress_tlen:	total data size handled by decompress requests
> + * @generate_tlen:	total data size of generated data by the RNG
> + * @hash_tlen:		total data size hashed
> + * @akcipher_err_cnt:	number of error for akcipher requests
> + * @cipher_err_cnt:	number of error for akcipher requests
> + * @compress_err_cnt:	number of error for akcipher requests
> + * @aead_err_cnt:	number of error for akcipher requests
> + * @hash_err_cnt:	number of error for akcipher requests
> + * @rng_err_cnt:	number of error for akcipher requests
> + * @kpp_err_cnt:	number of error for akcipher requests
> + *
>   * The struct crypto_alg describes a generic Crypto API algorithm and is common
>   * for all of the transformations. Any variable not documented here shall not
>   * be used by a cipher implementation as it is internal to the Crypto API.
> @@ -487,6 +514,45 @@ struct crypto_alg {
>  	void (*cra_destroy)(struct crypto_alg *alg);
>  	
>  	struct module *cra_module;
> +
> +	union {
> +		atomic_t encrypt_cnt;
> +		atomic_t compress_cnt;
> +		atomic_t generate_cnt;
> +		atomic_t hash_cnt;
> +		atomic_t setsecret_cnt;
> +	};
> +	union {
> +		atomic64_t encrypt_tlen;
> +		atomic64_t compress_tlen;
> +		atomic64_t generate_tlen;
> +		atomic64_t hash_tlen;
> +	};
> +	union {
> +		atomic_t akcipher_err_cnt;
> +		atomic_t cipher_err_cnt;
> +		atomic_t compress_err_cnt;
> +		atomic_t aead_err_cnt;
> +		atomic_t hash_err_cnt;
> +		atomic_t rng_err_cnt;
> +		atomic_t kpp_err_cnt;
> +	};
> +	union {
> +		atomic_t decrypt_cnt;
> +		atomic_t decompress_cnt;
> +		atomic_t seed_cnt;
> +		atomic_t generate_public_key_cnt;
> +	};
> +	union {
> +		atomic64_t decrypt_tlen;
> +		atomic64_t decompress_tlen;
> +	};
> +	union {
> +		atomic_t verify_cnt;
> +		atomic_t compute_shared_secret_cnt;
> +	};
> +	atomic_t sign_cnt;
> +
>  } CRYPTO_MINALIGN_ATTR;

The new fields here should all be behind CONFIG_CRYPTO_STATS.

Ideally there would be zero overhead when CONFIG_CRYPTO_STATS is disabled.
That's not quite the case currently.

- Eric

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 1/2] crypto: Implement a generic crypto statistics
  2018-09-19 10:10 ` [PATCH v3 1/2] " Corentin Labbe
  2018-11-03 22:19   ` Eric Biggers
@ 2018-11-03 22:52   ` Eric Biggers
  2018-11-04  9:12     ` LABBE Corentin
  2018-12-06  0:04   ` Eric Biggers
  2 siblings, 1 reply; 18+ messages in thread
From: Eric Biggers @ 2018-11-03 22:52 UTC (permalink / raw)
  To: Corentin Labbe; +Cc: davem, herbert, nhorman, linux-crypto, linux-kernel

On Wed, Sep 19, 2018 at 10:10:54AM +0000, Corentin Labbe wrote:
> diff --git a/include/uapi/linux/cryptouser.h b/include/uapi/linux/cryptouser.h
> index 19bf0ca6d635..6dafbc3e4414 100644
> --- a/include/uapi/linux/cryptouser.h
> +++ b/include/uapi/linux/cryptouser.h
> @@ -29,6 +29,7 @@ enum {
>  	CRYPTO_MSG_UPDATEALG,
>  	CRYPTO_MSG_GETALG,
>  	CRYPTO_MSG_DELRNG,
> +	CRYPTO_MSG_GETSTAT,
>  	__CRYPTO_MSG_MAX
>  };
>  #define CRYPTO_MSG_MAX (__CRYPTO_MSG_MAX - 1)
> @@ -50,6 +51,16 @@ enum crypto_attr_type_t {
>  	CRYPTOCFGA_REPORT_AKCIPHER,	/* struct crypto_report_akcipher */
>  	CRYPTOCFGA_REPORT_KPP,		/* struct crypto_report_kpp */
>  	CRYPTOCFGA_REPORT_ACOMP,	/* struct crypto_report_acomp */
> +	CRYPTOCFGA_STAT_LARVAL,		/* struct crypto_stat */
> +	CRYPTOCFGA_STAT_HASH,		/* struct crypto_stat */
> +	CRYPTOCFGA_STAT_BLKCIPHER,	/* struct crypto_stat */
> +	CRYPTOCFGA_STAT_AEAD,		/* struct crypto_stat */
> +	CRYPTOCFGA_STAT_COMPRESS,	/* struct crypto_stat */
> +	CRYPTOCFGA_STAT_RNG,		/* struct crypto_stat */
> +	CRYPTOCFGA_STAT_CIPHER,		/* struct crypto_stat */
> +	CRYPTOCFGA_STAT_AKCIPHER,	/* struct crypto_stat */
> +	CRYPTOCFGA_STAT_KPP,		/* struct crypto_stat */
> +	CRYPTOCFGA_STAT_ACOMP,		/* struct crypto_stat */
>  	__CRYPTOCFGA_MAX
>  
>  #define CRYPTOCFGA_MAX (__CRYPTOCFGA_MAX - 1)
> @@ -65,6 +76,47 @@ struct crypto_user_alg {
>  	__u32 cru_flags;
>  };
>  
> +struct crypto_stat {
> +	char type[CRYPTO_MAX_NAME];
> +	union {
> +		__u32 stat_encrypt_cnt;
> +		__u32 stat_compress_cnt;
> +		__u32 stat_generate_cnt;
> +		__u32 stat_hash_cnt;
> +		__u32 stat_setsecret_cnt;
> +	};
> +	union {
> +		__u64 stat_encrypt_tlen;
> +		__u64 stat_compress_tlen;
> +		__u64 stat_generate_tlen;
> +		__u64 stat_hash_tlen;
> +	};
> +	union {
> +		__u32 stat_akcipher_err_cnt;
> +		__u32 stat_cipher_err_cnt;
> +		__u32 stat_compress_err_cnt;
> +		__u32 stat_aead_err_cnt;
> +		__u32 stat_hash_err_cnt;
> +		__u32 stat_rng_err_cnt;
> +		__u32 stat_kpp_err_cnt;
> +	};
> +	union {
> +		__u32 stat_decrypt_cnt;
> +		__u32 stat_decompress_cnt;
> +		__u32 stat_seed_cnt;
> +		__u32 stat_generate_public_key_cnt;
> +	};
> +	union {
> +		__u64 stat_decrypt_tlen;
> +		__u64 stat_decompress_tlen;
> +	};
> +	union {
> +		__u32 stat_verify_cnt;
> +		__u32 stat_compute_shared_secret_cnt;
> +	};
> +	__u32 stat_sign_cnt;
> +};
> +

All the 32-bit fields need to be 64-bit.  In some cases, UINT32_MAX crypto
operations can be done in seconds.

It's also weird that everything shares the same crypto_stat structure.  I think
there should be a different struct for each algorithm type, like there is for
the existing crypto_user algorithm reporting.  In fact you are kind of already
doing that since the struct is loaded full of unions.  But it would be much
cleaner to use actually different structures.

- Eric

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 1/2] crypto: Implement a generic crypto statistics
  2018-11-03 22:19   ` Eric Biggers
@ 2018-11-04  9:11     ` LABBE Corentin
  0 siblings, 0 replies; 18+ messages in thread
From: LABBE Corentin @ 2018-11-04  9:11 UTC (permalink / raw)
  To: Eric Biggers; +Cc: davem, herbert, nhorman, linux-crypto, linux-kernel

On Sat, Nov 03, 2018 at 03:19:36PM -0700, Eric Biggers wrote:
> Hi Corentin,
> 
> On Wed, Sep 19, 2018 at 10:10:54AM +0000, Corentin Labbe wrote:
> > This patch implement a generic way to get statistics about all crypto
> > usages.
> > 
> > Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
> > ---
> >  crypto/Kconfig                               |  11 +
> >  crypto/Makefile                              |   1 +
> >  crypto/ahash.c                               |  21 +-
> >  crypto/algapi.c                              |   8 +
> >  crypto/{crypto_user.c => crypto_user_base.c} |   9 +-
> >  crypto/crypto_user_stat.c                    | 463 +++++++++++++++++++++++++++
> >  crypto/rng.c                                 |   1 +
> >  include/crypto/acompress.h                   |  38 ++-
> >  include/crypto/aead.h                        |  51 ++-
> >  include/crypto/akcipher.h                    |  76 ++++-
> >  include/crypto/hash.h                        |  32 +-
> >  include/crypto/internal/cryptouser.h         |   8 +
> >  include/crypto/kpp.h                         |  51 ++-
> >  include/crypto/rng.h                         |  29 +-
> >  include/crypto/skcipher.h                    |  44 ++-
> >  include/linux/crypto.h                       | 110 ++++++-
> >  include/uapi/linux/cryptouser.h              |  52 +++
> >  17 files changed, 970 insertions(+), 35 deletions(-)
> >  rename crypto/{crypto_user.c => crypto_user_base.c} (97%)
> >  create mode 100644 crypto/crypto_user_stat.c
> >  create mode 100644 include/crypto/internal/cryptouser.h
> > 
> > diff --git a/crypto/Kconfig b/crypto/Kconfig
> > index 90f2811fac5f..4ef95b0b25a3 100644
> > --- a/crypto/Kconfig
> > +++ b/crypto/Kconfig
> > @@ -1799,6 +1799,17 @@ config CRYPTO_USER_API_AEAD
> >  	  This option enables the user-spaces interface for AEAD
> >  	  cipher algorithms.
> >  
> > +config CRYPTO_STATS
> > +	bool "Crypto usage statistics for User-space"
> > +	help
> > +	  This option enables the gathering of crypto stats.
> > +	  This will collect:
> > +	  - encrypt/decrypt size and numbers of symmeric operations
> > +	  - compress/decompress size and numbers of compress operations
> > +	  - size and numbers of hash operations
> > +	  - encrypt/decrypt/sign/verify numbers for asymmetric operations
> > +	  - generate/seed numbers for rng operations
> > +
> >  config CRYPTO_HASH_INFO
> >  	bool
> >  
> > diff --git a/crypto/Makefile b/crypto/Makefile
> > index d719843f8b6e..ff5c2bbda04a 100644
> > --- a/crypto/Makefile
> > +++ b/crypto/Makefile
> > @@ -54,6 +54,7 @@ cryptomgr-y := algboss.o testmgr.o
> >  
> >  obj-$(CONFIG_CRYPTO_MANAGER2) += cryptomgr.o
> >  obj-$(CONFIG_CRYPTO_USER) += crypto_user.o
> > +crypto_user-y := crypto_user_base.o crypto_user_stat.o
> >  obj-$(CONFIG_CRYPTO_CMAC) += cmac.o
> >  obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
> >  obj-$(CONFIG_CRYPTO_VMAC) += vmac.o
> 
> Why is crypto_user_stat.c always being compiled when CONFIG_CRYPTO_USER is
> enabled, even when CONFIG_CRYPTO_STATS is not?
> 
> When CONFIG_CRYPTO_STATS is disabled, all the crypto stat stuff should be
> stubbed out so that crypto_user_stat.c doesn't need to be compiled.
> 
> [...]
> > diff --git a/include/linux/crypto.h b/include/linux/crypto.h
> > index e8839d3a7559..3634ad6fe202 100644
> > --- a/include/linux/crypto.h
> > +++ b/include/linux/crypto.h
> > @@ -454,6 +454,33 @@ struct compress_alg {
> >   * @cra_refcnt: internally used
> >   * @cra_destroy: internally used
> >   *
> > + * All following statistics are for this crypto_alg
> > + * @encrypt_cnt:	number of encrypt requests
> > + * @decrypt_cnt:	number of decrypt requests
> > + * @compress_cnt:	number of compress requests
> > + * @decompress_cnt:	number of decompress requests
> > + * @generate_cnt:	number of RNG generate requests
> > + * @seed_cnt:		number of times the rng was seeded
> > + * @hash_cnt:		number of hash requests
> > + * @sign_cnt:		number of sign requests
> > + * @setsecret_cnt:	number of setsecrey operation
> > + * @generate_public_key_cnt:	number of generate_public_key operation
> > + * @verify_cnt:			number of verify operation
> > + * @compute_shared_secret_cnt:	number of compute_shared_secret operation
> > + * @encrypt_tlen:	total data size handled by encrypt requests
> > + * @decrypt_tlen:	total data size handled by decrypt requests
> > + * @compress_tlen:	total data size handled by compress requests
> > + * @decompress_tlen:	total data size handled by decompress requests
> > + * @generate_tlen:	total data size of generated data by the RNG
> > + * @hash_tlen:		total data size hashed
> > + * @akcipher_err_cnt:	number of error for akcipher requests
> > + * @cipher_err_cnt:	number of error for akcipher requests
> > + * @compress_err_cnt:	number of error for akcipher requests
> > + * @aead_err_cnt:	number of error for akcipher requests
> > + * @hash_err_cnt:	number of error for akcipher requests
> > + * @rng_err_cnt:	number of error for akcipher requests
> > + * @kpp_err_cnt:	number of error for akcipher requests
> > + *
> >   * The struct crypto_alg describes a generic Crypto API algorithm and is common
> >   * for all of the transformations. Any variable not documented here shall not
> >   * be used by a cipher implementation as it is internal to the Crypto API.
> > @@ -487,6 +514,45 @@ struct crypto_alg {
> >  	void (*cra_destroy)(struct crypto_alg *alg);
> >  	
> >  	struct module *cra_module;
> > +
> > +	union {
> > +		atomic_t encrypt_cnt;
> > +		atomic_t compress_cnt;
> > +		atomic_t generate_cnt;
> > +		atomic_t hash_cnt;
> > +		atomic_t setsecret_cnt;
> > +	};
> > +	union {
> > +		atomic64_t encrypt_tlen;
> > +		atomic64_t compress_tlen;
> > +		atomic64_t generate_tlen;
> > +		atomic64_t hash_tlen;
> > +	};
> > +	union {
> > +		atomic_t akcipher_err_cnt;
> > +		atomic_t cipher_err_cnt;
> > +		atomic_t compress_err_cnt;
> > +		atomic_t aead_err_cnt;
> > +		atomic_t hash_err_cnt;
> > +		atomic_t rng_err_cnt;
> > +		atomic_t kpp_err_cnt;
> > +	};
> > +	union {
> > +		atomic_t decrypt_cnt;
> > +		atomic_t decompress_cnt;
> > +		atomic_t seed_cnt;
> > +		atomic_t generate_public_key_cnt;
> > +	};
> > +	union {
> > +		atomic64_t decrypt_tlen;
> > +		atomic64_t decompress_tlen;
> > +	};
> > +	union {
> > +		atomic_t verify_cnt;
> > +		atomic_t compute_shared_secret_cnt;
> > +	};
> > +	atomic_t sign_cnt;
> > +
> >  } CRYPTO_MINALIGN_ATTR;
> 
> The new fields here should all be behind CONFIG_CRYPTO_STATS.
> 
> Ideally there would be zero overhead when CONFIG_CRYPTO_STATS is disabled.
> That's not quite the case currently.
> 
> - Eric

Hello

I will address thoses problem in a followup patch.

Thanks

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 1/2] crypto: Implement a generic crypto statistics
  2018-11-03 22:52   ` Eric Biggers
@ 2018-11-04  9:12     ` LABBE Corentin
  0 siblings, 0 replies; 18+ messages in thread
From: LABBE Corentin @ 2018-11-04  9:12 UTC (permalink / raw)
  To: Eric Biggers; +Cc: davem, herbert, nhorman, linux-crypto, linux-kernel

On Sat, Nov 03, 2018 at 03:52:35PM -0700, Eric Biggers wrote:
> On Wed, Sep 19, 2018 at 10:10:54AM +0000, Corentin Labbe wrote:
> > diff --git a/include/uapi/linux/cryptouser.h b/include/uapi/linux/cryptouser.h
> > index 19bf0ca6d635..6dafbc3e4414 100644
> > --- a/include/uapi/linux/cryptouser.h
> > +++ b/include/uapi/linux/cryptouser.h
> > @@ -29,6 +29,7 @@ enum {
> >  	CRYPTO_MSG_UPDATEALG,
> >  	CRYPTO_MSG_GETALG,
> >  	CRYPTO_MSG_DELRNG,
> > +	CRYPTO_MSG_GETSTAT,
> >  	__CRYPTO_MSG_MAX
> >  };
> >  #define CRYPTO_MSG_MAX (__CRYPTO_MSG_MAX - 1)
> > @@ -50,6 +51,16 @@ enum crypto_attr_type_t {
> >  	CRYPTOCFGA_REPORT_AKCIPHER,	/* struct crypto_report_akcipher */
> >  	CRYPTOCFGA_REPORT_KPP,		/* struct crypto_report_kpp */
> >  	CRYPTOCFGA_REPORT_ACOMP,	/* struct crypto_report_acomp */
> > +	CRYPTOCFGA_STAT_LARVAL,		/* struct crypto_stat */
> > +	CRYPTOCFGA_STAT_HASH,		/* struct crypto_stat */
> > +	CRYPTOCFGA_STAT_BLKCIPHER,	/* struct crypto_stat */
> > +	CRYPTOCFGA_STAT_AEAD,		/* struct crypto_stat */
> > +	CRYPTOCFGA_STAT_COMPRESS,	/* struct crypto_stat */
> > +	CRYPTOCFGA_STAT_RNG,		/* struct crypto_stat */
> > +	CRYPTOCFGA_STAT_CIPHER,		/* struct crypto_stat */
> > +	CRYPTOCFGA_STAT_AKCIPHER,	/* struct crypto_stat */
> > +	CRYPTOCFGA_STAT_KPP,		/* struct crypto_stat */
> > +	CRYPTOCFGA_STAT_ACOMP,		/* struct crypto_stat */
> >  	__CRYPTOCFGA_MAX
> >  
> >  #define CRYPTOCFGA_MAX (__CRYPTOCFGA_MAX - 1)
> > @@ -65,6 +76,47 @@ struct crypto_user_alg {
> >  	__u32 cru_flags;
> >  };
> >  
> > +struct crypto_stat {
> > +	char type[CRYPTO_MAX_NAME];
> > +	union {
> > +		__u32 stat_encrypt_cnt;
> > +		__u32 stat_compress_cnt;
> > +		__u32 stat_generate_cnt;
> > +		__u32 stat_hash_cnt;
> > +		__u32 stat_setsecret_cnt;
> > +	};
> > +	union {
> > +		__u64 stat_encrypt_tlen;
> > +		__u64 stat_compress_tlen;
> > +		__u64 stat_generate_tlen;
> > +		__u64 stat_hash_tlen;
> > +	};
> > +	union {
> > +		__u32 stat_akcipher_err_cnt;
> > +		__u32 stat_cipher_err_cnt;
> > +		__u32 stat_compress_err_cnt;
> > +		__u32 stat_aead_err_cnt;
> > +		__u32 stat_hash_err_cnt;
> > +		__u32 stat_rng_err_cnt;
> > +		__u32 stat_kpp_err_cnt;
> > +	};
> > +	union {
> > +		__u32 stat_decrypt_cnt;
> > +		__u32 stat_decompress_cnt;
> > +		__u32 stat_seed_cnt;
> > +		__u32 stat_generate_public_key_cnt;
> > +	};
> > +	union {
> > +		__u64 stat_decrypt_tlen;
> > +		__u64 stat_decompress_tlen;
> > +	};
> > +	union {
> > +		__u32 stat_verify_cnt;
> > +		__u32 stat_compute_shared_secret_cnt;
> > +	};
> > +	__u32 stat_sign_cnt;
> > +};
> > +
> 
> All the 32-bit fields need to be 64-bit.  In some cases, UINT32_MAX crypto
> operations can be done in seconds.
> 
> It's also weird that everything shares the same crypto_stat structure.  I think
> there should be a different struct for each algorithm type, like there is for
> the existing crypto_user algorithm reporting.  In fact you are kind of already
> doing that since the struct is loaded full of unions.  But it would be much
> cleaner to use actually different structures.
> 
> - Eric

Hello

I agree, separate structures will be cleaner.
I will address this in a followup patch.

Thanks

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 1/2] crypto: Implement a generic crypto statistics
  2018-09-19 10:10 ` [PATCH v3 1/2] " Corentin Labbe
  2018-11-03 22:19   ` Eric Biggers
  2018-11-03 22:52   ` Eric Biggers
@ 2018-12-06  0:04   ` Eric Biggers
  2018-12-06 11:08     ` LABBE Corentin
  2 siblings, 1 reply; 18+ messages in thread
From: Eric Biggers @ 2018-12-06  0:04 UTC (permalink / raw)
  To: Corentin Labbe; +Cc: davem, herbert, nhorman, linux-crypto, linux-kernel

Hi Corentin,

On Wed, Sep 19, 2018 at 10:10:54AM +0000, Corentin Labbe wrote:
> +int crypto_dump_reportstat(struct sk_buff *skb, struct netlink_callback *cb)
> +{
> +	struct crypto_alg *alg;
> +	struct crypto_dump_info info;
> +	int err;
> +
> +	if (cb->args[0])
> +		goto out;
> +
> +	cb->args[0] = 1;
> +
> +	info.in_skb = cb->skb;
> +	info.out_skb = skb;
> +	info.nlmsg_seq = cb->nlh->nlmsg_seq;
> +	info.nlmsg_flags = NLM_F_MULTI;
> +
> +	list_for_each_entry(alg, &crypto_alg_list, cra_list) {
> +		err = crypto_reportstat_alg(alg, &info);
> +		if (err)
> +			goto out_err;
> +	}
> +
> +out:
> +	return skb->len;
> +out_err:
> +	return err;
> +}
> +
> +int crypto_dump_reportstat_done(struct netlink_callback *cb)
> +{
> +	return 0;
> +}

How did you test this part?  Hint: these functions are never executed.

- Eric

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 1/2] crypto: Implement a generic crypto statistics
  2018-12-06  0:04   ` Eric Biggers
@ 2018-12-06 11:08     ` LABBE Corentin
  0 siblings, 0 replies; 18+ messages in thread
From: LABBE Corentin @ 2018-12-06 11:08 UTC (permalink / raw)
  To: Eric Biggers; +Cc: davem, herbert, nhorman, linux-crypto, linux-kernel

On Wed, Dec 05, 2018 at 04:04:59PM -0800, Eric Biggers wrote:
> Hi Corentin,
> 
> On Wed, Sep 19, 2018 at 10:10:54AM +0000, Corentin Labbe wrote:
> > +int crypto_dump_reportstat(struct sk_buff *skb, struct netlink_callback *cb)
> > +{
> > +	struct crypto_alg *alg;
> > +	struct crypto_dump_info info;
> > +	int err;
> > +
> > +	if (cb->args[0])
> > +		goto out;
> > +
> > +	cb->args[0] = 1;
> > +
> > +	info.in_skb = cb->skb;
> > +	info.out_skb = skb;
> > +	info.nlmsg_seq = cb->nlh->nlmsg_seq;
> > +	info.nlmsg_flags = NLM_F_MULTI;
> > +
> > +	list_for_each_entry(alg, &crypto_alg_list, cra_list) {
> > +		err = crypto_reportstat_alg(alg, &info);
> > +		if (err)
> > +			goto out_err;
> > +	}
> > +
> > +out:
> > +	return skb->len;
> > +out_err:
> > +	return err;
> > +}
> > +
> > +int crypto_dump_reportstat_done(struct netlink_callback *cb)
> > +{
> > +	return 0;
> > +}
> 
> How did you test this part?  Hint: these functions are never executed.
> 

Right, it is not used, only crypto_reportstat is used by the getstat.c example tool.
And for using it, I need to do changes in crypto_user_rcv_msg().
But I am not sure if it is interesting to do so.

So I will send a patch for removing it.

Regards

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2018-12-06 11:09 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-19 10:10 [PATCH v3 0/2] crypto: Implement a generic crypto statistics Corentin Labbe
2018-09-19 10:10 ` [PATCH v3 1/2] " Corentin Labbe
2018-11-03 22:19   ` Eric Biggers
2018-11-04  9:11     ` LABBE Corentin
2018-11-03 22:52   ` Eric Biggers
2018-11-04  9:12     ` LABBE Corentin
2018-12-06  0:04   ` Eric Biggers
2018-12-06 11:08     ` LABBE Corentin
2018-09-19 10:10 ` [PATCH v3 2/2] crypto: tools: Add cryptostat userspace Corentin Labbe
2018-09-28 13:13   ` Ard Biesheuvel
2018-09-28 13:13     ` Ard Biesheuvel
2018-09-28 17:03     ` Ard Biesheuvel
2018-09-28 17:03       ` Ard Biesheuvel
2018-10-01  7:20       ` LABBE Corentin
2018-10-01  7:20         ` LABBE Corentin
2018-10-01  8:40         ` Ard Biesheuvel
2018-10-01  8:40           ` Ard Biesheuvel
2018-09-28  5:08 ` [PATCH v3 0/2] crypto: Implement a generic crypto statistics Herbert Xu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.