xref: /aosp_15_r20/external/trace-cmd/tracecmd/trace-vsock.c (revision 58e6ee5f017f6a8912852c892d18457e4bafb554)
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