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