177 lines
3.3 KiB
C
177 lines
3.3 KiB
C
|
|
#include <unistd.h>
|
||
|
|
#include <errno.h>
|
||
|
|
#include <arpa/inet.h>
|
||
|
|
#include <sys/ioctl.h>
|
||
|
|
#include <linux/vm_sockets.h>
|
||
|
|
|
||
|
|
#include "trace-cmd-private.h"
|
||
|
|
|
||
|
|
int __hidden trace_vsock_open(unsigned int cid, unsigned int port)
|
||
|
|
{
|
||
|
|
struct sockaddr_vm addr = {
|
||
|
|
.svm_family = AF_VSOCK,
|
||
|
|
.svm_cid = cid,
|
||
|
|
.svm_port = port,
|
||
|
|
};
|
||
|
|
int sd;
|
||
|
|
|
||
|
|
sd = socket(AF_VSOCK, SOCK_STREAM, 0);
|
||
|
|
if (sd < 0)
|
||
|
|
return -errno;
|
||
|
|
|
||
|
|
if (connect(sd, (struct sockaddr *)&addr, sizeof(addr)))
|
||
|
|
return -errno;
|
||
|
|
|
||
|
|
return sd;
|
||
|
|
}
|
||
|
|
|
||
|
|
int __hidden trace_vsock_make(unsigned int port)
|
||
|
|
{
|
||
|
|
struct sockaddr_vm addr = {
|
||
|
|
.svm_family = AF_VSOCK,
|
||
|
|
.svm_cid = VMADDR_CID_ANY,
|
||
|
|
.svm_port = port,
|
||
|
|
};
|
||
|
|
int sd;
|
||
|
|
|
||
|
|
sd = socket(AF_VSOCK, SOCK_STREAM, 0);
|
||
|
|
if (sd < 0)
|
||
|
|
return -errno;
|
||
|
|
|
||
|
|
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));
|
||
|
|
|
||
|
|
if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)))
|
||
|
|
return -errno;
|
||
|
|
|
||
|
|
if (listen(sd, SOMAXCONN))
|
||
|
|
return -errno;
|
||
|
|
|
||
|
|
return sd;
|
||
|
|
}
|
||
|
|
|
||
|
|
int __hidden trace_vsock_make_any(void)
|
||
|
|
{
|
||
|
|
return trace_vsock_make(VMADDR_PORT_ANY);
|
||
|
|
}
|
||
|
|
|
||
|
|
int __hidden trace_vsock_get_port(int sd, unsigned int *port)
|
||
|
|
{
|
||
|
|
struct sockaddr_vm addr;
|
||
|
|
socklen_t addr_len = sizeof(addr);
|
||
|
|
|
||
|
|
if (getsockname(sd, (struct sockaddr *)&addr, &addr_len))
|
||
|
|
return -errno;
|
||
|
|
|
||
|
|
if (addr.svm_family != AF_VSOCK)
|
||
|
|
return -EINVAL;
|
||
|
|
|
||
|
|
if (port)
|
||
|
|
*port = addr.svm_port;
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int get_vsocket_params(int fd, unsigned int *lcid, unsigned int *rcid)
|
||
|
|
{
|
||
|
|
struct sockaddr_vm addr;
|
||
|
|
socklen_t addr_len = sizeof(addr);
|
||
|
|
|
||
|
|
memset(&addr, 0, sizeof(addr));
|
||
|
|
if (getsockname(fd, (struct sockaddr *)&addr, &addr_len))
|
||
|
|
return -1;
|
||
|
|
if (addr.svm_family != AF_VSOCK)
|
||
|
|
return -1;
|
||
|
|
*lcid = addr.svm_cid;
|
||
|
|
|
||
|
|
memset(&addr, 0, sizeof(addr));
|
||
|
|
addr_len = sizeof(addr);
|
||
|
|
if (getpeername(fd, (struct sockaddr *)&addr, &addr_len))
|
||
|
|
return -1;
|
||
|
|
if (addr.svm_family != AF_VSOCK)
|
||
|
|
return -1;
|
||
|
|
*rcid = addr.svm_cid;
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int trace_vsock_print_connection(int fd)
|
||
|
|
{
|
||
|
|
struct sockaddr_vm vm_addr;
|
||
|
|
socklen_t addr_len;
|
||
|
|
int cid, port;
|
||
|
|
|
||
|
|
addr_len = sizeof(vm_addr);
|
||
|
|
if (getpeername(fd, (struct sockaddr *)&vm_addr, &addr_len))
|
||
|
|
return -1;
|
||
|
|
if (vm_addr.svm_family != AF_VSOCK)
|
||
|
|
return -1;
|
||
|
|
cid = vm_addr.svm_cid;
|
||
|
|
port = vm_addr.svm_port;
|
||
|
|
if (tracecmd_get_debug())
|
||
|
|
tracecmd_debug("Connected to @%u:%u fd:%d\n", cid, port, fd);
|
||
|
|
else
|
||
|
|
tracecmd_plog("Connected to @%u:%u\n", cid, port);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int try_splice_read_vsock(void)
|
||
|
|
{
|
||
|
|
int ret, sd, brass[2];
|
||
|
|
|
||
|
|
sd = socket(AF_VSOCK, SOCK_STREAM, 0);
|
||
|
|
if (sd < 0)
|
||
|
|
return -errno;
|
||
|
|
|
||
|
|
ret = pipe(brass);
|
||
|
|
if (ret < 0)
|
||
|
|
goto out_close_sd;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* On kernels that don't support splice reading from vsockets
|
||
|
|
* this will fail with EINVAL, or ENOTCONN otherwise.
|
||
|
|
* Technically, it should never succeed but if it does, claim splice
|
||
|
|
* reading is supported.
|
||
|
|
*/
|
||
|
|
ret = splice(sd, NULL, brass[1], NULL, 10, 0);
|
||
|
|
if (ret < 0)
|
||
|
|
ret = errno != EINVAL;
|
||
|
|
else
|
||
|
|
ret = 1;
|
||
|
|
|
||
|
|
close(brass[0]);
|
||
|
|
close(brass[1]);
|
||
|
|
out_close_sd:
|
||
|
|
close(sd);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool __hidden trace_vsock_can_splice_read(void)
|
||
|
|
{
|
||
|
|
static bool initialized, res;
|
||
|
|
|
||
|
|
if (initialized)
|
||
|
|
return res;
|
||
|
|
|
||
|
|
res = try_splice_read_vsock() > 0;
|
||
|
|
initialized = true;
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
|
||
|
|
#define GET_LOCAL_CID 0x7b9
|
||
|
|
|
||
|
|
int __hidden trace_vsock_local_cid(void)
|
||
|
|
{
|
||
|
|
int cid;
|
||
|
|
int fd;
|
||
|
|
|
||
|
|
fd = open("/dev/vsock", O_RDONLY);
|
||
|
|
if (fd < 0)
|
||
|
|
return -errno;
|
||
|
|
|
||
|
|
if (ioctl(fd, GET_LOCAL_CID, &cid))
|
||
|
|
cid = -errno;
|
||
|
|
|
||
|
|
close(fd);
|
||
|
|
return cid;
|
||
|
|
}
|