• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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