aboutsummaryrefslogtreecommitdiff
path: root/tracecmd/trace-vsock.c
diff options
context:
space:
mode:
Diffstat (limited to 'tracecmd/trace-vsock.c')
-rw-r--r--tracecmd/trace-vsock.c176
1 files changed, 176 insertions, 0 deletions
diff --git a/tracecmd/trace-vsock.c b/tracecmd/trace-vsock.c
new file mode 100644
index 00000000..39294e7a
--- /dev/null
+++ b/tracecmd/trace-vsock.c
@@ -0,0 +1,176 @@
+#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;
+}