blob: 39294e7a2a3c4999a2420aa565486f5867544e48 [file] [log] [blame]
#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;
}