Add a common helper to connect to a vsock endpoint by CID and port.
This can be used by both the daemon (guest agent over vsock) and tools
(e.g. SSH-over-vsock command execution).
It raises no libvirt errors and preserves errno, making it suitable for
probing service availability without spamming the log. An
error-reporting counterpart can be added alongside once a caller needs
one.
We use SO_VM_SOCKETS_CONNECT_TIMEOUT to cap the worst-case wait to
200ms. Best case is still immediate (when the service is present or
when the kernel early-returns in case the guest isn't ready).
Signed-off-by: Polina Vishneva <polina.vishneva@virtuozzo.com>
---
src/libvirt_private.syms | 1 +
src/util/virvsock.c | 69 ++++++++++++++++++++++++++++++++++++++++
src/util/virvsock.h | 6 ++++
3 files changed, 76 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index c76e5cb08a..6a9cd34134 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -3842,6 +3842,7 @@ virPCIVPDResourceUpdateKeyword;
# util/virvsock.h
virVsockAcquireGuestCid;
+virVsockConnectQuiet;
virVsockSetGuestCid;
diff --git a/src/util/virvsock.c b/src/util/virvsock.c
index c6f8b362b8..10ca1d44eb 100644
--- a/src/util/virvsock.c
+++ b/src/util/virvsock.c
@@ -23,11 +23,15 @@
#ifdef __linux__
# include <linux/vhost.h>
+# include <sys/socket.h>
+# include <linux/time_types.h>
+# include <linux/vm_sockets.h>
#endif
#include "virvsock.h"
#include "virerror.h"
+#include "virfile.h"
#include "virlog.h"
@@ -105,3 +109,68 @@ virVsockAcquireGuestCid(int fd,
return 0;
}
+
+
+#ifdef __linux__
+
+/* Use the _OLD option with a __kernel_old_timeval: _NEW takes a 64-bit
+ * __kernel_sock_timeval which is more awkward to build, and glibc's struct
+ * timeval is 64-bit under _TIME_BITS=64 on 32-bit, which the _OLD option
+ * misreads. */
+#ifndef SO_VM_SOCKETS_CONNECT_TIMEOUT_OLD
+# define SO_VM_SOCKETS_CONNECT_TIMEOUT_OLD SO_VM_SOCKETS_CONNECT_TIMEOUT
+#endif
+
+/**
+ * virVsockConnectQuiet:
+ * @cid: guest context ID
+ * @port: vsock port number
+ *
+ * Connect to a vsock endpoint identified by @cid and @port.
+ * Doesn't raise any errors. Preserves the actual errno on error.
+ *
+ * Returns: connected fd on success, -1 on error.
+ */
+int
+virVsockConnectQuiet(unsigned int cid,
+ unsigned int port)
+{
+ struct sockaddr_vm addr = {
+ .svm_family = AF_VSOCK,
+ .svm_cid = cid,
+ .svm_port = port,
+ };
+ struct __kernel_old_timeval tv = {
+ .tv_sec = VIR_VSOCK_CONNECT_TIMEOUT_MS / 1000,
+ .tv_usec = (VIR_VSOCK_CONNECT_TIMEOUT_MS % 1000) * 1000,
+ };
+ int fd;
+
+ if ((fd = socket(AF_VSOCK, SOCK_STREAM | SOCK_CLOEXEC, 0)) < 0)
+ return -1;
+
+ if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_CONNECT_TIMEOUT_OLD,
+ &tv, sizeof(tv)) < 0)
+ goto error;
+
+ if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+ goto error;
+
+ return fd;
+
+ error:
+ VIR_FORCE_CLOSE(fd);
+ return -1;
+}
+
+#else /* !__linux__ */
+
+int
+virVsockConnectQuiet(unsigned int cid G_GNUC_UNUSED,
+ unsigned int port G_GNUC_UNUSED)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+#endif /* !__linux__ */
diff --git a/src/util/virvsock.h b/src/util/virvsock.h
index d6ba2faabf..06c251b594 100644
--- a/src/util/virvsock.h
+++ b/src/util/virvsock.h
@@ -18,6 +18,8 @@
#pragma once
+#define VIR_VSOCK_CONNECT_TIMEOUT_MS 200
+
int
virVsockSetGuestCid(int fd,
unsigned int guest_cid);
@@ -25,3 +27,7 @@ virVsockSetGuestCid(int fd,
int
virVsockAcquireGuestCid(int fd,
unsigned int *guest_cid);
+
+int
+virVsockConnectQuiet(unsigned int cid,
+ unsigned int port);
--
2.54.0