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