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 | |