Commit 5c5945dc authored by Xiaoyan Li's avatar Xiaoyan Li Committed by Paolo Abeni
Browse files

selftests/net: Add SHA256 computation over data sent in tcp_mmap



Add option to compute and send SHA256 over data sent (-i).

This is to ensure the correctness of data received.
Data is randomly populated from /dev/urandom.

Tested:
./tcp_mmap -s -z -i
./tcp_mmap -z -H $ADDR -i
SHA256 is correct

./tcp_mmap -s -i
./tcp_mmap -H $ADDR -i
SHA256 is correct

Signed-off-by: default avatarCoco Li <lixiaoyan@google.com>
Reviewed-by: default avatarEric Dumazet <edumazet@google.com>
Link: https://lore.kernel.org/r/20230321081202.2370275-2-lixiaoyan@google.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 593ef60c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -89,7 +89,7 @@ TEST_FILES := settings
include ../lib.mk

$(OUTPUT)/reuseport_bpf_numa: LDLIBS += -lnuma
$(OUTPUT)/tcp_mmap: LDLIBS += -lpthread
$(OUTPUT)/tcp_mmap: LDLIBS += -lpthread -lcrypto
$(OUTPUT)/tcp_inq: LDLIBS += -lpthread
$(OUTPUT)/bind_bhash: LDLIBS += -lpthread

+91 −11
Original line number Diff line number Diff line
@@ -66,11 +66,16 @@
#include <poll.h>
#include <linux/tcp.h>
#include <assert.h>
#include <openssl/pem.h>

#ifndef MSG_ZEROCOPY
#define MSG_ZEROCOPY    0x4000000
#endif

#ifndef min
#define min(a, b)  ((a) < (b) ? (a) : (b))
#endif

#define FILE_SZ (1ULL << 35)
static int cfg_family = AF_INET6;
static socklen_t cfg_alen = sizeof(struct sockaddr_in6);
@@ -81,12 +86,14 @@ static int sndbuf; /* Default: autotuning. Can be set with -w <integer> option
static int zflg; /* zero copy option. (MSG_ZEROCOPY for sender, mmap() for receiver */
static int xflg; /* hash received data (simple xor) (-h option) */
static int keepflag; /* -k option: receiver shall keep all received file in memory (no munmap() calls) */
static int integrity; /* -i option: sender and receiver compute sha256 over the data.*/

static size_t chunk_size  = 512*1024;

static size_t map_align;

unsigned long htotal;
unsigned int digest_len;

static inline void prefetch(const void *x)
{
@@ -148,12 +155,14 @@ static void *mmap_large_buffer(size_t need, size_t *allocated)

void *child_thread(void *arg)
{
	unsigned char digest[SHA256_DIGEST_LENGTH];
	unsigned long total_mmap = 0, total = 0;
	struct tcp_zerocopy_receive zc;
	unsigned char *buffer = NULL;
	unsigned long delta_usec;
	EVP_MD_CTX *ctx = NULL;
	int flags = MAP_SHARED;
	struct timeval t0, t1;
	char *buffer = NULL;
	void *raddr = NULL;
	void *addr = NULL;
	double throughput;
@@ -180,6 +189,14 @@ void *child_thread(void *arg)
			addr = ALIGN_PTR_UP(raddr, map_align);
		}
	}
	if (integrity) {
		ctx = EVP_MD_CTX_new();
		if (!ctx) {
			perror("cannot enable SHA computing");
			goto error;
		}
		EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
	}
	while (1) {
		struct pollfd pfd = { .fd = fd, .events = POLLIN, };
		int sub;
@@ -191,7 +208,7 @@ void *child_thread(void *arg)

			memset(&zc, 0, sizeof(zc));
			zc.address = (__u64)((unsigned long)addr);
			zc.length = chunk_size;
			zc.length = min(chunk_size, FILE_SZ - lu);

			res = getsockopt(fd, IPPROTO_TCP, TCP_ZEROCOPY_RECEIVE,
					 &zc, &zc_len);
@@ -200,6 +217,8 @@ void *child_thread(void *arg)

			if (zc.length) {
				assert(zc.length <= chunk_size);
				if (integrity)
					EVP_DigestUpdate(ctx, addr, zc.length);
				total_mmap += zc.length;
				if (xflg)
					hash_zone(addr, zc.length);
@@ -211,22 +230,30 @@ void *child_thread(void *arg)
			}
			if (zc.recv_skip_hint) {
				assert(zc.recv_skip_hint <= chunk_size);
				lu = read(fd, buffer, zc.recv_skip_hint);
				lu = read(fd, buffer, min(zc.recv_skip_hint,
							  FILE_SZ - total));
				if (lu > 0) {
					if (integrity)
						EVP_DigestUpdate(ctx, buffer, lu);
					if (xflg)
						hash_zone(buffer, lu);
					total += lu;
				}
				if (lu == 0)
					goto end;
			}
			continue;
		}
		sub = 0;
		while (sub < chunk_size) {
			lu = read(fd, buffer + sub, chunk_size - sub);
			lu = read(fd, buffer + sub, min(chunk_size - sub,
							FILE_SZ - total));
			if (lu == 0)
				goto end;
			if (lu < 0)
				break;
			if (integrity)
				EVP_DigestUpdate(ctx, buffer + sub, lu);
			if (xflg)
				hash_zone(buffer + sub, lu);
			total += lu;
@@ -237,6 +264,20 @@ void *child_thread(void *arg)
	gettimeofday(&t1, NULL);
	delta_usec = (t1.tv_sec - t0.tv_sec) * 1000000 + t1.tv_usec - t0.tv_usec;

	if (integrity) {
		fcntl(fd, F_SETFL, 0);
		EVP_DigestFinal_ex(ctx, digest, &digest_len);
		lu = read(fd, buffer, SHA256_DIGEST_LENGTH);
		if (lu != SHA256_DIGEST_LENGTH)
			perror("Error: Cannot read SHA256\n");

		if (memcmp(digest, buffer,
			   SHA256_DIGEST_LENGTH))
			fprintf(stderr, "Error: SHA256 of the data is not right\n");
		else
			printf("\nSHA256 is correct\n");
	}

	throughput = 0;
	if (delta_usec)
		throughput = total * 8.0 / (double)delta_usec / 1000.0;
@@ -368,19 +409,38 @@ static unsigned long default_huge_page_size(void)
	return hps;
}

static void randomize(void *target, size_t count)
{
	static int urandom = -1;
	ssize_t got;

	urandom = open("/dev/urandom", O_RDONLY);
	if (urandom < 0) {
		perror("open /dev/urandom");
		exit(1);
	}
	got = read(urandom, target, count);
	if (got != count) {
		perror("read /dev/urandom");
		exit(1);
	}
}

int main(int argc, char *argv[])
{
	unsigned char digest[SHA256_DIGEST_LENGTH];
	struct sockaddr_storage listenaddr, addr;
	unsigned int max_pacing_rate = 0;
	EVP_MD_CTX *ctx = NULL;
	unsigned char *buffer;
	uint64_t total = 0;
	char *host = NULL;
	int fd, c, on = 1;
	size_t buffer_sz;
	char *buffer;
	int sflg = 0;
	int mss = 0;

	while ((c = getopt(argc, argv, "46p:svr:w:H:zxkP:M:C:a:")) != -1) {
	while ((c = getopt(argc, argv, "46p:svr:w:H:zxkP:M:C:a:i")) != -1) {
		switch (c) {
		case '4':
			cfg_family = PF_INET;
@@ -426,6 +486,9 @@ int main(int argc, char *argv[])
		case 'a':
			map_align = atol(optarg);
			break;
		case 'i':
			integrity = 1;
			break;
		default:
			exit(1);
		}
@@ -468,7 +531,7 @@ int main(int argc, char *argv[])
	}

	buffer = mmap_large_buffer(chunk_size, &buffer_sz);
	if (buffer == (char *)-1) {
	if (buffer == (unsigned char *)-1) {
		perror("mmap");
		exit(1);
	}
@@ -501,17 +564,34 @@ int main(int argc, char *argv[])
		perror("setsockopt SO_ZEROCOPY, (-z option disabled)");
		zflg = 0;
	}
	if (integrity) {
		randomize(buffer, buffer_sz);
		ctx = EVP_MD_CTX_new();
		if (!ctx) {
			perror("cannot enable SHA computing");
			exit(1);
		}
		EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
	}
	while (total < FILE_SZ) {
		size_t offset = total % chunk_size;
		int64_t wr = FILE_SZ - total;

		if (wr > chunk_size)
			wr = chunk_size;
		/* Note : we just want to fill the pipe with 0 bytes */
		wr = send(fd, buffer, (size_t)wr, zflg ? MSG_ZEROCOPY : 0);
		if (wr > chunk_size - offset)
			wr = chunk_size - offset;
		/* Note : we just want to fill the pipe with random bytes */
		wr = send(fd, buffer + offset,
			  (size_t)wr, zflg ? MSG_ZEROCOPY : 0);
		if (wr <= 0)
			break;
		if (integrity)
			EVP_DigestUpdate(ctx, buffer + offset, wr);
		total += wr;
	}
	if (integrity && total == FILE_SZ) {
		EVP_DigestFinal_ex(ctx, digest, &digest_len);
		send(fd, digest, (size_t)SHA256_DIGEST_LENGTH, 0);
	}
	close(fd);
	munmap(buffer, buffer_sz);
	return 0;