Subject: Re: [PATCH 0/3] crypto: algif - change algif_skcipher to be asynchronous

From: Tadeusz Struk <[email-masked]>
Date: Mon, 02 Feb 2015 07:03:02 -0800

On 02/01/2015 10:31 AM, Stephan Mueller wrote:
> Hi Tadeusz,
> 
>> > The way the algif_skcipher works currently is that on sendmsg/sendpage it
>> > builds an sgl for the input data and then on read/recvmsg it sends the job
>> > for encryption putting the user to sleep till the data is processed.
>> > This way it can only handle one job at a given time.
>> > To be able to fuly utilize the potential of existing crypto hardware
>> > accelerators it is required to submit multiple jobs in asynchronously.
>> > First patch enables asynchronous read and write on socket.
>> > Second patch enables af_alg sgl to be linked.
>> > Third patch implement asynch read for skcipher.
> Do you have a code fragment on how to test that patch? I would like to see 
> whether I can test that with my libkcapi.

Hi Stephan,
This is what I'm using.

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/types.h>
#include <linux/aio_abi.h>
#include <sys/syscall.h>
#include <sys/uio.h>

#define SOL_ALG 279

#define SPLICE_F_GIFT	(0x08)	/* pages passed in are a gift */
struct sockaddr_alg {
	__u16	salg_family;
	__u8	salg_type[14];
	__u32	salg_feat;
	__u32	salg_mask;
	__u8	salg_name[64];
};
struct af_alg_iv {
	__u32	ivlen;
	__u8	iv[0];
};
/* Socket options */
#define ALG_SET_KEY			1
#define ALG_SET_IV			2
#define ALG_SET_OP			3
#define ALG_SET_AEAD_ASSOCLEN		4
#define ALG_SET_AEAD_AUTHSIZE		5

/* Operations */
#define ALG_OP_DECRYPT			0
#define ALG_OP_ENCRYPT			1

#define BUFFSIZE (4096)
//#define BUFFSIZE (4096)
#define PKGSIZE (4096)

#define INFLIGTHS 256
#define TO_SEND (1024 * 1024)
//#define OUT_OFFSET 2048;
//#define IN_OFFSET 4064;
#define OUT_OFFSET 0;
#define IN_OFFSET 0;

static char buf[BUFFSIZE] __attribute__((__aligned__(BUFFSIZE)));
static char *buf_out = buf;

static inline int io_setup(unsigned n, aio_context_t *ctx)
{
	return syscall(__NR_io_setup, n, ctx);
}

static inline int io_destroy(aio_context_t ctx)
{
	return syscall(__NR_io_destroy, ctx);
}

static inline int io_read(aio_context_t ctx, long n,  struct iocb **iocb)
{
	return syscall(__NR_io_submit, ctx, n, iocb);
}

static inline int io_getevents(aio_context_t ctx, long min, long max,
			struct io_event *events, struct timespec *timeout)
{
	return syscall(__NR_io_getevents, ctx, min, max, events, timeout);
}

static inline int eventfd(int n)
{
	return syscall(__NR_eventfd, n);
}

static int crypt_kernel(const char *key, char *oiv, int zcp)
{
	int opfd;
	int tfmfd;
	int efd;
	struct timespec timeout;
	fd_set rfds;
        struct timeval tv;
	struct sockaddr_alg sa = {
		.salg_family = AF_ALG,
		.salg_type = "skcipher",
		.salg_name = "cbc(aes)"
	};
	struct msghdr msg = {};
	struct cmsghdr *cmsg;
	char cbuf[CMSG_SPACE(4) + CMSG_SPACE(20)] = {};
	struct aes_iv {
		__u32 len;
		__u8 iv[16];
	} *iv;
	struct iovec iov;
	int pipes[2];
	aio_context_t aio_ctx;
	struct iocb *cb;
	struct iocb cbt[INFLIGTHS];
	struct io_event events[INFLIGTHS];
	unsigned int received = 0;
	int i, r;

	timeout.tv_sec = 0;
	timeout.tv_nsec = 0;
	pipe(pipes);
	memset(cbt, 0, sizeof(cbt));
	efd = eventfd(0);
	tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
	bind(tfmfd, (struct sockaddr *)&sa, sizeof(sa));
	setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY, key, 16);
	opfd = accept(tfmfd, NULL, 0);

	msg.msg_control = cbuf;
	msg.msg_controllen = sizeof(cbuf);

	cmsg = CMSG_FIRSTHDR(&msg);
	cmsg->cmsg_level = SOL_ALG;
	cmsg->cmsg_type = ALG_SET_OP;
	cmsg->cmsg_len = CMSG_LEN(4);
	*(__u32 *)CMSG_DATA(cmsg) = ALG_OP_ENCRYPT;

	cmsg = CMSG_NXTHDR(&msg, cmsg);
	cmsg->cmsg_level = SOL_ALG;
	cmsg->cmsg_type = ALG_SET_IV;
	cmsg->cmsg_len = CMSG_LEN(20);
	iv = (void *)CMSG_DATA(cmsg);
	iv->len = 16;
	memcpy(iv->iv, oiv, 16);

	iov.iov_base = buf + IN_OFFSET;
	iov.iov_len = PKGSIZE;
	msg.msg_flags = MSG_MORE;

	aio_ctx = 0;
	r = io_setup(INFLIGTHS, &aio_ctx);
	if (r < 0) {
		perror("io_setup error");
		return -1;
	}

	for (i = 0; i < TO_SEND; i++) {
		if (zcp) {
			msg.msg_iovlen = 0;
			msg.msg_iov = NULL;

			r = sendmsg(opfd, &msg, 0);
			if (r < 0)
				printf("sendmsg returned Error: %d\n", errno);

			r = vmsplice(pipes[1], &iov, 1, SPLICE_F_GIFT);
			if (r < 0)
				printf("vmsplice returned Error: %d\n", errno);

			r = splice(pipes[0], NULL, opfd, NULL, PKGSIZE, 0);
			if (r < 0)
				printf("splice returned Error: %d\n", errno);
		} else {
			msg.msg_iovlen = 1;
			msg.msg_iov = &iov;
			r = sendmsg(opfd, &msg, PKGSIZE);
			if (r < 0)
				printf("zero cp sendmsg returned Error: %d\n", errno);
		}

		cb = &cbt[i % INFLIGTHS];
		if (cb->aio_fildes) {
			printf("req %d not processed yet???\n", i - INFLIGTHS);
			return -1;
		}
		memset(cb, '\0', sizeof(*cb));
		cb->aio_fildes = opfd;
		cb->aio_lio_opcode = IOCB_CMD_PREAD;
		cb->aio_buf = (unsigned long)buf_out + OUT_OFFSET;
		cb->aio_offset = 0;
		cb->aio_nbytes = PKGSIZE;
		cb->aio_flags = IOCB_FLAG_RESFD;
		cb->aio_resfd = efd;
		r = io_read(aio_ctx, 1, &cb);
		if (r != 1) {
			if (r < 0) {
				printf("io_read Error: %d\n", errno);
				return -1;
			} else {
				printf("Could not sumbit AIO read\n");
				return -1;
			}
		}

		FD_ZERO(&rfds);
		FD_SET(efd, &rfds);
		tv.tv_sec = 0;
		tv.tv_usec = 0;
		r = select(efd + 1, &rfds, NULL, NULL, &tv);

		if (r == -1) {
			printf("Select Error: %d\n", errno);
			return -1;
		} else if (FD_ISSET(efd, &rfds)) {
			r = io_getevents(aio_ctx, 1, INFLIGTHS, events + (received % INFLIGTHS),
					 &timeout);
			if (r > 0) {
				int y;

				for (y = 0; y < r; y++) {
					cb = (void*) events[(received + y) % INFLIGTHS].obj;
					cb->aio_fildes = 0;
					if (events[(received + y) % INFLIGTHS].res)
						printf("req %d failed\n", received + y);
				}
				received += r;
			} else if (r < 0) {
				printf("io_getevents Error: %d\n", errno);
				return -1;
			}
		}

		if (i == 0) {
			msg.msg_control = NULL;
			msg.msg_controllen = 0;
		}
	}

	while (received != TO_SEND) {
		r = io_getevents(aio_ctx, 1, TO_SEND - received,
				events + (received % INFLIGTHS), NULL);
		if (r > 0)
			received += r;
	}
	printf("All done!\n");
	close(efd);
	close(opfd);
	close(tfmfd);
	close(pipes[0]);
	close(pipes[1]);
	io_destroy(aio_ctx);
	return 0;
}

int main(int argc, char **argv)
{
	const char key[16] =
		"\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
		"\x51\x2e\x03\xd5\x34\x12\x00\x06";
	char iv[16] =
		"\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
		"\xb4\x22\xda\x80\x2c\x9f\xac\x41";

	memcpy(buf, "Single block msg", 16);

	if (argc == 2) {
		printf("zero copy\n");
		crypt_kernel(key, iv, 1);
	}
	else {
		printf("copy\n");
		crypt_kernel(key, iv, 0);
	}
	return 0;
}