xref: /linux/tools/testing/vsock/msg_zerocopy_common.c (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Some common code for MSG_ZEROCOPY logic
3  *
4  * Copyright (C) 2023 SberDevices.
5  *
6  * Author: Arseniy Krasnov <avkrasnov@salutedevices.com>
7  */
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <linux/errqueue.h>
14 
15 #include "msg_zerocopy_common.h"
16 
17 void enable_so_zerocopy(int fd)
18 {
19 	int val = 1;
20 
21 	if (setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, &val, sizeof(val))) {
22 		perror("setsockopt");
23 		exit(EXIT_FAILURE);
24 	}
25 }
26 
27 void vsock_recv_completion(int fd, const bool *zerocopied)
28 {
29 	struct sock_extended_err *serr;
30 	struct msghdr msg = { 0 };
31 	char cmsg_data[128];
32 	struct cmsghdr *cm;
33 	ssize_t res;
34 
35 	msg.msg_control = cmsg_data;
36 	msg.msg_controllen = sizeof(cmsg_data);
37 
38 	res = recvmsg(fd, &msg, MSG_ERRQUEUE);
39 	if (res) {
40 		fprintf(stderr, "failed to read error queue: %zi\n", res);
41 		exit(EXIT_FAILURE);
42 	}
43 
44 	cm = CMSG_FIRSTHDR(&msg);
45 	if (!cm) {
46 		fprintf(stderr, "cmsg: no cmsg\n");
47 		exit(EXIT_FAILURE);
48 	}
49 
50 	if (cm->cmsg_level != SOL_VSOCK) {
51 		fprintf(stderr, "cmsg: unexpected 'cmsg_level'\n");
52 		exit(EXIT_FAILURE);
53 	}
54 
55 	if (cm->cmsg_type != VSOCK_RECVERR) {
56 		fprintf(stderr, "cmsg: unexpected 'cmsg_type'\n");
57 		exit(EXIT_FAILURE);
58 	}
59 
60 	serr = (void *)CMSG_DATA(cm);
61 	if (serr->ee_origin != SO_EE_ORIGIN_ZEROCOPY) {
62 		fprintf(stderr, "serr: wrong origin: %u\n", serr->ee_origin);
63 		exit(EXIT_FAILURE);
64 	}
65 
66 	if (serr->ee_errno) {
67 		fprintf(stderr, "serr: wrong error code: %u\n", serr->ee_errno);
68 		exit(EXIT_FAILURE);
69 	}
70 
71 	/* This flag is used for tests, to check that transmission was
72 	 * performed as expected: zerocopy or fallback to copy. If NULL
73 	 * - don't care.
74 	 */
75 	if (!zerocopied)
76 		return;
77 
78 	if (*zerocopied && (serr->ee_code & SO_EE_CODE_ZEROCOPY_COPIED)) {
79 		fprintf(stderr, "serr: was copy instead of zerocopy\n");
80 		exit(EXIT_FAILURE);
81 	}
82 
83 	if (!*zerocopied && !(serr->ee_code & SO_EE_CODE_ZEROCOPY_COPIED)) {
84 		fprintf(stderr, "serr: was zerocopy instead of copy\n");
85 		exit(EXIT_FAILURE);
86 	}
87 }
88