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