1 #include <unistd.h>
2 #include <errno.h>
3 #include <arpa/inet.h>
4 #include <sys/ioctl.h>
5 #include <linux/vm_sockets.h>
6
7 #include "trace-cmd-private.h"
8
trace_vsock_open(unsigned int cid,unsigned int port)9 int __hidden trace_vsock_open(unsigned int cid, unsigned int port)
10 {
11 struct sockaddr_vm addr = {
12 .svm_family = AF_VSOCK,
13 .svm_cid = cid,
14 .svm_port = port,
15 };
16 int sd;
17
18 sd = socket(AF_VSOCK, SOCK_STREAM, 0);
19 if (sd < 0)
20 return -errno;
21
22 if (connect(sd, (struct sockaddr *)&addr, sizeof(addr))) {
23 close(sd);
24 return -errno;
25 }
26
27 return sd;
28 }
29
trace_vsock_make(unsigned int port)30 int __hidden trace_vsock_make(unsigned int port)
31 {
32 struct sockaddr_vm addr = {
33 .svm_family = AF_VSOCK,
34 .svm_cid = VMADDR_CID_ANY,
35 .svm_port = port,
36 };
37 int sd;
38
39 sd = socket(AF_VSOCK, SOCK_STREAM, 0);
40 if (sd < 0)
41 return -errno;
42
43 setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));
44
45 if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)))
46 goto error;
47
48 if (listen(sd, SOMAXCONN))
49 goto error;
50
51 return sd;
52
53 error:
54 close(sd);
55 return -errno;
56 }
57
trace_vsock_make_any(void)58 int __hidden trace_vsock_make_any(void)
59 {
60 return trace_vsock_make(VMADDR_PORT_ANY);
61 }
62
trace_vsock_get_port(int sd,unsigned int * port)63 int __hidden trace_vsock_get_port(int sd, unsigned int *port)
64 {
65 struct sockaddr_vm addr;
66 socklen_t addr_len = sizeof(addr);
67
68 if (getsockname(sd, (struct sockaddr *)&addr, &addr_len))
69 return -errno;
70
71 if (addr.svm_family != AF_VSOCK)
72 return -EINVAL;
73
74 if (port)
75 *port = addr.svm_port;
76
77 return 0;
78 }
79
get_vsocket_params(int fd,unsigned int * lcid,unsigned int * rcid)80 int get_vsocket_params(int fd, unsigned int *lcid, unsigned int *rcid)
81 {
82 struct sockaddr_vm addr;
83 socklen_t addr_len = sizeof(addr);
84
85 if (lcid) {
86 memset(&addr, 0, sizeof(addr));
87 if (getsockname(fd, (struct sockaddr *)&addr, &addr_len))
88 return -1;
89 if (addr.svm_family != AF_VSOCK)
90 return -1;
91 *lcid = addr.svm_cid;
92 }
93
94 if (rcid) {
95 memset(&addr, 0, sizeof(addr));
96 addr_len = sizeof(addr);
97 if (getpeername(fd, (struct sockaddr *)&addr, &addr_len))
98 return -1;
99 if (addr.svm_family != AF_VSOCK)
100 return -1;
101 *rcid = addr.svm_cid;
102 }
103
104 return 0;
105 }
106
trace_vsock_print_connection(int fd)107 int trace_vsock_print_connection(int fd)
108 {
109 struct sockaddr_vm vm_addr;
110 socklen_t addr_len;
111 int cid, port;
112
113 addr_len = sizeof(vm_addr);
114 if (getpeername(fd, (struct sockaddr *)&vm_addr, &addr_len))
115 return -1;
116 if (vm_addr.svm_family != AF_VSOCK)
117 return -1;
118 cid = vm_addr.svm_cid;
119 port = vm_addr.svm_port;
120 if (tracecmd_get_debug())
121 tracecmd_debug("Connected to @%u:%u fd:%d\n", cid, port, fd);
122 else
123 tracecmd_plog("Connected to @%u:%u\n", cid, port);
124 return 0;
125 }
126
try_splice_read_vsock(void)127 static int try_splice_read_vsock(void)
128 {
129 int ret, sd, brass[2];
130
131 sd = socket(AF_VSOCK, SOCK_STREAM, 0);
132 if (sd < 0)
133 return -errno;
134
135 ret = pipe(brass);
136 if (ret < 0)
137 goto out_close_sd;
138
139 /*
140 * On kernels that don't support splice reading from vsockets
141 * this will fail with EINVAL, or ENOTCONN otherwise.
142 * Technically, it should never succeed but if it does, claim splice
143 * reading is supported.
144 */
145 ret = splice(sd, NULL, brass[1], NULL, 10, 0);
146 if (ret < 0)
147 ret = errno != EINVAL;
148 else
149 ret = 1;
150
151 close(brass[0]);
152 close(brass[1]);
153 out_close_sd:
154 close(sd);
155 return ret;
156 }
157
trace_vsock_can_splice_read(void)158 bool __hidden trace_vsock_can_splice_read(void)
159 {
160 static bool initialized, res;
161
162 if (initialized)
163 return res;
164
165 res = try_splice_read_vsock() > 0;
166 initialized = true;
167 return res;
168 }
169
170 #define GET_LOCAL_CID 0x7b9
171
trace_vsock_local_cid(void)172 int __hidden trace_vsock_local_cid(void)
173 {
174 int cid;
175 int fd;
176
177 fd = open("/dev/vsock", O_RDONLY);
178 if (fd < 0)
179 return -errno;
180
181 if (ioctl(fd, GET_LOCAL_CID, &cid))
182 cid = -errno;
183
184 close(fd);
185 return cid;
186 }
187