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 <[email protected]>
---
 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

Reply via email to