mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Reviewed-by: Holger Dengler <dengler@linux.ibm.com> Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
567 lines
15 KiB
C
567 lines
15 KiB
C
/*
|
|
* cpacfstats - display and maintain CPACF perf counters
|
|
*
|
|
* cpacfstats client implementation
|
|
*
|
|
* Copyright IBM Corp. 2015, 2022
|
|
*
|
|
* s390-tools is free software; you can redistribute it and/or modify
|
|
* it under the terms of the MIT license. See LICENSE for details.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <getopt.h>
|
|
#include <getopt.h>
|
|
#define __STDC_FORMAT_MACROS
|
|
#include <inttypes.h>
|
|
#include <stdarg.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "lib/zt_common.h"
|
|
#include "cpacfstats.h"
|
|
|
|
|
|
static const char *const name = "cpacfstats";
|
|
|
|
static const char *const usage =
|
|
"Usage: %s [OPTIONS [COUNTER]]\n"
|
|
"\n"
|
|
"Enable, disable, reset and read CPACF Crypto Activity Counters\n"
|
|
"Use OPTIONS described below:\n"
|
|
"\n"
|
|
"\t-h, --help Print this help, then exit\n"
|
|
"\t-v, --version Print version information, then exit\n"
|
|
"\t-e, --enable [counter] Enable one or all counters\n"
|
|
"\t-d, --disable [counter] Disable one or all counters\n"
|
|
"\t-r, --reset [counter] Reset one or all counter values\n"
|
|
"\t-p, --print [counter] Print one or all counter values\n"
|
|
"\t-n, --nonzero Print all PAI counters\n"
|
|
"\t-j, --json Print all counter values in JSON format\n"
|
|
"\tcounter can be: 'aes' 'des' 'rng' 'sha' 'ecc'\n"
|
|
"\t 'pai_user' 'pai_kernel' or 'all'\n";
|
|
|
|
static const char *const counter_str[] = {
|
|
[DES_FUNCTIONS] = "des",
|
|
[AES_FUNCTIONS] = "aes",
|
|
[SHA_FUNCTIONS] = "sha",
|
|
[PRNG_FUNCTIONS] = "rng",
|
|
[ECC_FUNCTIONS] = "ecc",
|
|
[ALL_COUNTER] = "all",
|
|
[PAI_USER] = "pai_user",
|
|
[PAI_KERNEL] = "pai_kernel"
|
|
};
|
|
|
|
/* Strings for the pai counter details. Note that this is 0-based
|
|
* while PoP is 1-based.
|
|
*/
|
|
static const char *const pai_str[] = {
|
|
[ 0] = "KM DES",
|
|
[ 1] = "KM 2key TDES",
|
|
[ 2] = "KM TDES",
|
|
[ 3] = "KM DES protected key",
|
|
[ 4] = "KM 2key TDES protected key",
|
|
[ 5] = "KM TDES protected key",
|
|
[ 6] = "KM AES 128bit",
|
|
[ 7] = "KM AES 192bit",
|
|
[ 8] = "KM AES 256bit",
|
|
[ 9] = "KM AES 128bit protected key",
|
|
[ 10] = "KM AES 192bit protected key",
|
|
[ 11] = "KM AES 256bit protected key",
|
|
[ 12] = "KM AES-XTS 128bit",
|
|
[ 13] = "KM AES-XTS 256bit",
|
|
[ 14] = "KM AES-XTS 128bit protected key",
|
|
[ 15] = "KM AES-XTS 256bit protected key",
|
|
[ 16] = "KMC DES",
|
|
[ 17] = "KMC 2key TDES",
|
|
[ 18] = "KMC TDES",
|
|
[ 19] = "KMC DES protected key",
|
|
[ 20] = "KMC 2key TDES protected key",
|
|
[ 21] = "KMC TDES protected key",
|
|
[ 22] = "KMC AES 128bit",
|
|
[ 23] = "KMC AES 192bit",
|
|
[ 24] = "KMC AES 256bit",
|
|
[ 25] = "KMC AES 128bit protected key",
|
|
[ 26] = "KMC AES 192bit protected key",
|
|
[ 27] = "KMC AES 256bit protected key",
|
|
[ 28] = "KMC PRNG",
|
|
[ 29] = "KMA AES 128bit",
|
|
[ 30] = "KMA AES 192bit",
|
|
[ 31] = "KMA AES 256bit",
|
|
[ 32] = "KMA AES 128bit protected key",
|
|
[ 33] = "KMA AES 192bit protected key",
|
|
[ 34] = "KMA AES 256bit protected key",
|
|
[ 35] = "KMF DES",
|
|
[ 36] = "KMF 2key TDES",
|
|
[ 37] = "KMF TDES",
|
|
[ 38] = "KMF DES protected key",
|
|
[ 39] = "KMF 2key TDES protected key",
|
|
[ 40] = "KMF TDES protected key",
|
|
[ 41] = "KMF AES 128bit",
|
|
[ 42] = "KMF AES 192bit",
|
|
[ 43] = "KMF AES 256bit",
|
|
[ 44] = "KMF AES 128bit protected key",
|
|
[ 45] = "KMF AES 192bit protected key",
|
|
[ 46] = "KMF AES 256bit protected key",
|
|
[ 47] = "KMCTR DES",
|
|
[ 48] = "KMCTR 2key TDES",
|
|
[ 49] = "KMCTR TDES",
|
|
[ 50] = "KMCTR DES protected key",
|
|
[ 51] = "KMCTR 2key TDES protected key",
|
|
[ 52] = "KMCTR TDES protected key",
|
|
[ 53] = "KMCTR AES 128bit",
|
|
[ 54] = "KMCTR AES 192bit",
|
|
[ 55] = "KMCTR AES 256bit",
|
|
[ 56] = "KMCTR AES 128bit protected key",
|
|
[ 57] = "KMCTR AES 192bit protected key",
|
|
[ 58] = "KMCTR AES 256bit protected key",
|
|
[ 59] = "KMO DES",
|
|
[ 60] = "KMO 2key TDES",
|
|
[ 61] = "KMO TDES",
|
|
[ 62] = "KMO DES protected key",
|
|
[ 63] = "KMO 2key TDES protected key",
|
|
[ 64] = "KMO TDES protected key",
|
|
[ 65] = "KMO AES 128bit",
|
|
[ 66] = "KMO AES 192bit",
|
|
[ 67] = "KMO AES 256bit",
|
|
[ 68] = "KMO AES 128bit protected key",
|
|
[ 69] = "KMO AES 192bit protected key",
|
|
[ 70] = "KMO AES 256bit protected key",
|
|
[ 71] = "KIMD SHA1",
|
|
[ 72] = "KIMD SHA256",
|
|
[ 73] = "KIMD SHA512",
|
|
[ 74] = "KIMD SHA3-224",
|
|
[ 75] = "KIMD SHA3-256",
|
|
[ 76] = "KIMD SHA3-384",
|
|
[ 77] = "KIMD SHA3-512",
|
|
[ 78] = "KIMD SHAKE 128",
|
|
[ 79] = "KIMD SHAKE 256",
|
|
[ 80] = "KIMD GHASH",
|
|
[ 81] = "KLMD SHA1",
|
|
[ 82] = "KLMD SHA256",
|
|
[ 83] = "KLMD SHA512",
|
|
[ 84] = "KLMD SHA3-224",
|
|
[ 85] = "KLMD SHA3-256",
|
|
[ 86] = "KLMD SHA3-384",
|
|
[ 87] = "KLMD SHA3-512",
|
|
[ 88] = "KLMD SHAKE 128",
|
|
[ 89] = "KLMD SHAKE 256",
|
|
[ 90] = "KMAC DES",
|
|
[ 91] = "KMAC 2key TDES",
|
|
[ 92] = "KMAC TDES",
|
|
[ 93] = "KMAC DES protected key",
|
|
[ 94] = "KMAC 2key TDES protected key",
|
|
[ 95] = "KMAC TDES protected key",
|
|
[ 96] = "KMAC AES 128bit",
|
|
[ 97] = "KMAC AES 192bit",
|
|
[ 98] = "KMAC AES 256bit",
|
|
[ 99] = "KMAC AES 128bit protected key",
|
|
[100] = "KMAC AES 192bit protected key",
|
|
[101] = "KMAC AES 256bit protected key",
|
|
[102] = "PCC Last Block CMAC DES",
|
|
[103] = "PCC Last Block CMAC 2key TDES",
|
|
[104] = "PCC Last Block CMAC TDES",
|
|
[105] = "PCC Last Block CMAC DES protected key",
|
|
[106] = "PCC Last Block CMAC 2key TDES protected key",
|
|
[107] = "PCC Last Block CMAC TDES protected key",
|
|
[108] = "PCC Last Block CMAC AES 128bit",
|
|
[109] = "PCC Last Block CMAC AES 192bit",
|
|
[110] = "PCC Last Block CMAC AES 256bit",
|
|
[111] = "PCC Last Block CMAC AES 128bit protected key",
|
|
[112] = "PCC Last Block CMAC AES 192bit protected key",
|
|
[113] = "PCC Last Block CMAC AES 256bit protected key",
|
|
[114] = "PCC XTS Parameter AES 128bit",
|
|
[115] = "PCC XTS Parameter AES 256bit",
|
|
[116] = "PCC XTS Parameter AES 128bit protected key",
|
|
[117] = "PCC XTS Parameter AES 256bit protected key",
|
|
[118] = "PCC Scalar Mult P256",
|
|
[119] = "PCC Scalar Mult P384",
|
|
[120] = "PCC Scalar Mult P521",
|
|
[121] = "PCC Scalar Mult Ed25519",
|
|
[122] = "PCC Scalar Mult Ed448",
|
|
[123] = "PCC Scalar Mult X25519",
|
|
[124] = "PCC Scalar Mult X448",
|
|
[125] = "PRNO SHA512 DRNG",
|
|
[126] = "PRNO TRNG Query Ratio",
|
|
[127] = "PRNO TRNG",
|
|
[128] = "KDSA ECDSA Verify P256",
|
|
[129] = "KDSA ECDSA Verify P384",
|
|
[130] = "KDSA ECDSA Verify P521",
|
|
[131] = "KDSA ECDSA Sign P256",
|
|
[132] = "KDSA ECDSA Sign P384",
|
|
[133] = "KDSA ECDSA Sign P521",
|
|
[134] = "KDSA ECDSA Sign P256 protected key",
|
|
[135] = "KDSA ECDSA Sign P384 protected key",
|
|
[136] = "KDSA ECDSA Sign P521 protected key",
|
|
[137] = "KDSA EdDSA Verify Ed25519",
|
|
[138] = "KDSA EdDSA Verify Ed448",
|
|
[139] = "KDSA EdDSA Sign Ed25519",
|
|
[140] = "KDSA EdDSA Sign Ed448",
|
|
[141] = "KDSA EdDSA Sign Ed25519 protected key",
|
|
[142] = "KDSA EdDSA Sign Ed448 protected key",
|
|
[143] = "PCKMO DES",
|
|
[144] = "PCKMO 2key TDES",
|
|
[145] = "PCMKO TDES",
|
|
[146] = "PCKMO AES 128bit",
|
|
[147] = "PCKMO AES 192bit",
|
|
[148] = "PCMKO AES 256bit",
|
|
[149] = "PCKMO ECC P256",
|
|
[150] = "PCKMO ECC P384",
|
|
[151] = "PCKMO ECC P521",
|
|
[152] = "PCKMO ECC Ed25519",
|
|
[153] = "PCKMO ECC Ed448",
|
|
[154] = "Reserved 1",
|
|
[155] = "Reserved 2"
|
|
};
|
|
|
|
|
|
static int paiprintnonzero;
|
|
|
|
|
|
static int send_query(int s, enum cmd_e cmd, enum ctr_e ctr)
|
|
{
|
|
struct msg m;
|
|
|
|
memset(&m, 0, sizeof(m));
|
|
|
|
m.head.m_ver = VERSION;
|
|
m.head.m_type = QUERY;
|
|
m.query.m_ctr = ctr;
|
|
m.query.m_cmd = cmd;
|
|
|
|
return send_msg(s, &m, 0);
|
|
}
|
|
|
|
|
|
static int recv_answer(int s, int *ctr, int *state, uint64_t *value)
|
|
{
|
|
struct msg m;
|
|
int rc;
|
|
|
|
rc = recv_msg(s, &m, 0);
|
|
if (rc == 0) {
|
|
if (m.head.m_ver != VERSION) {
|
|
eprint("Received msg with wrong version %d != %d\n",
|
|
m.head.m_ver, VERSION);
|
|
return -1;
|
|
}
|
|
if (m.head.m_type != ANSWER) {
|
|
eprint("Received msg with wrong type %d != %d\n",
|
|
m.head.m_type, ANSWER);
|
|
return -1;
|
|
}
|
|
*ctr = m.answer.m_ctr;
|
|
*state = m.answer.m_state;
|
|
*value = m.answer.m_value;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static void printjsonsep(void)
|
|
{
|
|
static const char *jsonsep = "";
|
|
|
|
fputs(jsonsep, stdout);
|
|
jsonsep = ",";
|
|
}
|
|
|
|
|
|
static void json_print_virtual_counter_answer(int s, int ctr,
|
|
int state, uint64_t value)
|
|
{
|
|
int paictr = 0, paistate = 0, ec;
|
|
uint64_t i, paivalue = 0, maxnum;
|
|
const char *space;
|
|
|
|
switch (ctr) {
|
|
case HOTPLUG_DETECTED:
|
|
printjsonsep();
|
|
printf("{\"counter\":\"hotplug detected\",");
|
|
if (state < 0)
|
|
printf("\"error\":%d}", state);
|
|
else
|
|
printf("\"value\":%d}", !!value);
|
|
return;
|
|
case PAI_USER:
|
|
maxnum = NUM_PAI_USER;
|
|
space = "user";
|
|
break;
|
|
case PAI_KERNEL:
|
|
maxnum = NUM_PAI_KERNEL;
|
|
space = "kernel";
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
/* Here, we have validated the PAI counter retrieved, but not
|
|
* yet printed. */
|
|
if (state != ENABLED)
|
|
return;
|
|
if (value > maxnum) {
|
|
eprint("Incompatible versions detected!\n");
|
|
eprint("Expected %"PRIu64" counter space for %s, but got %"PRIu64"\n",
|
|
maxnum, space, value);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
for (i = 0; i < value; ++i) {
|
|
ec = recv_answer(s, &paictr, &paistate, &paivalue);
|
|
if (ec < 0 || paistate < 0) {
|
|
eprint("Error on receiving answer message from daemon\n");
|
|
/* No more data for this virtual event after error. */
|
|
return;
|
|
}
|
|
if (paictr > NUM_PAI_KERNEL) {
|
|
eprint("Pai counter number too big: %d\n", paictr);
|
|
} else {
|
|
printjsonsep();
|
|
printf("{\"counter\":\"%s\",\"space\":\"%s\",\"counterid\":%d,",
|
|
pai_str[paictr], space, paictr + 1);
|
|
if (paistate < 0) {
|
|
printf("\"error\":%d}", paistate);
|
|
/* Protocol does not send further counters. */
|
|
return;
|
|
}
|
|
printf("\"value\":%"PRIu64"}", paivalue);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void print_virtual_counter_answer(int s,
|
|
int ctr, int state, uint64_t value)
|
|
{
|
|
static const char *const states[] = {
|
|
[DISABLED] = "disabled",
|
|
[ENABLED] = "enabled",
|
|
[UNSUPPORTED] = "unsupported"
|
|
};
|
|
int paictr = 0, paistate = 0, ec;
|
|
uint64_t i, paivalue = 0, maxnum;
|
|
const char *ctrstr;
|
|
|
|
switch (ctr) {
|
|
case HOTPLUG_DETECTED:
|
|
if (state >= 0 && value > 0)
|
|
printf(" hotplug detected\n");
|
|
return;
|
|
case PAI_USER:
|
|
maxnum = NUM_PAI_USER;
|
|
ctrstr = "pai_user";
|
|
break;
|
|
case PAI_KERNEL:
|
|
maxnum = NUM_PAI_KERNEL;
|
|
ctrstr = "pai_kernel";
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
/* Here, we have validated the PAI counter retrieved, but not
|
|
* yet printed. */
|
|
if (state < 0 || state > UNSUPPORTED) {
|
|
printf(" %11s: error state %d\n", ctrstr, state);
|
|
/* No details follow if counter in error state. */
|
|
return;
|
|
}
|
|
printf(" %-11s: %s\n", ctrstr, states[state]);
|
|
if (state != ENABLED)
|
|
return;
|
|
if (value > maxnum) {
|
|
eprint("Incompatible versions detected!\n");
|
|
eprint("Expected %"PRIu64" counters for %s, but got %"PRIu64"\n",
|
|
maxnum, ctrstr, value);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
for (i = 0; i < value; ++i) {
|
|
ec = recv_answer(s, &paictr, &paistate, &paivalue);
|
|
if (ec < 0 || paistate < 0) {
|
|
eprint("Error on receiving answer message from daemon\n");
|
|
/* No more data for this virtual event after error. */
|
|
return;
|
|
}
|
|
if (paictr > NUM_PAI_KERNEL)
|
|
eprint("Pai counter number too big: %d\n", paictr);
|
|
else if (!paiprintnonzero || paivalue > 0)
|
|
printf(" %-45s: %"PRIu64"\n", pai_str[paictr], paivalue);
|
|
}
|
|
}
|
|
|
|
static void print_answer(int s, int ctr, int state, uint64_t value)
|
|
{
|
|
if (ctr > ALL_COUNTER)
|
|
print_virtual_counter_answer(s, ctr, state, value);
|
|
else if (state < 0)
|
|
printf(" %s counter: error state %d\n",
|
|
counter_str[ctr], state);
|
|
else if (state == DISABLED)
|
|
printf(" %s counter: disabled\n", counter_str[ctr]);
|
|
else if (state == UNSUPPORTED)
|
|
printf(" %s counter: unsupported\n", counter_str[ctr]);
|
|
else
|
|
printf(" %s counter: %"PRIu64"\n", counter_str[ctr], value);
|
|
}
|
|
|
|
|
|
static void json_print_answer(int s, int ctr, int state, uint64_t value)
|
|
{
|
|
if (ctr > ALL_COUNTER) {
|
|
json_print_virtual_counter_answer(s, ctr, state, value);
|
|
} else if (state < 0) {
|
|
printjsonsep();
|
|
printf("{\"counter\":\"%s\",", counter_str[ctr]);
|
|
printf("\"error\":%d}\n", state);
|
|
} else if (state == ENABLED) {
|
|
printjsonsep();
|
|
printf("{\"counter\":\"%s\",", counter_str[ctr]);
|
|
printf("\"value\":%"PRIu64"}", value);
|
|
}
|
|
}
|
|
|
|
|
|
int eprint(const char *format, ...)
|
|
{
|
|
char buf[1024];
|
|
va_list vargs;
|
|
int i, n;
|
|
|
|
i = snprintf(buf, sizeof(buf), "%s: ", name);
|
|
va_start(vargs, format);
|
|
n = vsnprintf(buf+i, sizeof(buf)-i, format, vargs);
|
|
va_end(vargs);
|
|
|
|
if (n > 0)
|
|
fputs(buf, stderr);
|
|
|
|
return n;
|
|
}
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
enum ctr_e ctr = ALL_COUNTER;
|
|
enum cmd_e cmd = PRINT;
|
|
int i, j, s, state, num, json = 0;
|
|
uint64_t value;
|
|
|
|
if (argc > 1) {
|
|
int opt, idx = 0;
|
|
const struct option long_opts[] = {
|
|
{ "help", 0, NULL, 'h' },
|
|
{ "version", 0, NULL, 'v' },
|
|
{ "enable", 0, NULL, 'e' },
|
|
{ "disable", 0, NULL, 'd' },
|
|
{ "reset", 0, NULL, 'r' },
|
|
{ "print", 0, NULL, 'p' },
|
|
{ "nonzero", 0, NULL, 'n' },
|
|
{ "json", 0, NULL, 'j' },
|
|
{ NULL, 0, NULL, 0 } };
|
|
while (1) {
|
|
opt = getopt_long(argc, argv,
|
|
"hvedrpnj", long_opts, &idx);
|
|
if (opt == -1)
|
|
break; /* no more arguments */
|
|
switch (opt) {
|
|
case 'h':
|
|
printf(usage, name);
|
|
return 0;
|
|
case 'v':
|
|
printf("%s: Linux on System z CPACF Crypto Activity Counters Client\n"
|
|
"Version %s\n%s\n",
|
|
name, RELEASE_STRING, COPYRIGHT);
|
|
return 0;
|
|
case 'e':
|
|
cmd = ENABLE;
|
|
json = 0;
|
|
break;
|
|
case 'd':
|
|
cmd = DISABLE;
|
|
json = 0;
|
|
break;
|
|
case 'r':
|
|
cmd = RESET;
|
|
break;
|
|
case 'p':
|
|
cmd = PRINT;
|
|
json = 0;
|
|
break;
|
|
case 'n':
|
|
paiprintnonzero = 1;
|
|
break;
|
|
case 'j':
|
|
cmd = PRINT;
|
|
json = 1;
|
|
break;
|
|
default:
|
|
eprint("Invalid argument, try -h or --help for more information\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
/* there may be an optional counter argument */
|
|
if (optind > 0 && optind < argc) {
|
|
for (i = 0; i < NUM_COUNTER; i++)
|
|
if (strcmp(argv[optind], counter_str[i]) == 0)
|
|
break;
|
|
if (i >= NUM_COUNTER) {
|
|
eprint("Unknown counter '%s'\n", argv[optind]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
ctr = (enum ctr_e) i;
|
|
}
|
|
}
|
|
if (json)
|
|
ctr = ALL_COUNTER;
|
|
|
|
/* try to open and connect socket to the cpacfstatsd daemon */
|
|
s = open_socket(CLIENT);
|
|
if (s < 0) {
|
|
eprint("Can't connect to daemon\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/* send query */
|
|
if (send_query(s, cmd, ctr) != 0) {
|
|
eprint("Error on sending query message to daemon\n");
|
|
close(s);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (ctr == ALL_COUNTER) {
|
|
/* The -1 is for ALL_COUNTER which is not sent, +1 for
|
|
* hotplug state. */
|
|
num = NUM_COUNTER - 1 + 1;
|
|
} else {
|
|
/* +1 for hotplug state */
|
|
num = 1 + 1;
|
|
}
|
|
if (json)
|
|
putchar('[');
|
|
for (i = 0; i < num; i++) {
|
|
/* receive answer */
|
|
if (recv_answer(s, &j, &state, &value) != 0) {
|
|
eprint("Error on receiving answer message from daemon\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (state < 0) {
|
|
eprint("Received bad status code %d from daemon\n",
|
|
state);
|
|
close(s);
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (json)
|
|
json_print_answer(s, j, state, value);
|
|
else
|
|
print_answer(s, j, state, value);
|
|
}
|
|
if (json)
|
|
putchar(']');
|
|
|
|
/* close connection */
|
|
close(s);
|
|
|
|
return 0;
|
|
}
|