From: Oliver Kurth Date: Wed, 4 Mar 2020 20:07:13 +0000 (-0800) Subject: Send GUESTRPCPKT_FIELD_FAST_CLOSE when doing one-off RPC via vsock X-Git-Tag: stable-11.1.0~48 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bf9de87b3cd4d25e6ca23db63c01f353acf40419;p=thirdparty%2Fopen-vm-tools.git Send GUESTRPCPKT_FIELD_FAST_CLOSE when doing one-off RPC via vsock To work around a vsock/vmci/VMX issue with vsock cleanup, send a special command that tells the VXM to immediately close a vsock after completing an RPC. This minimizes delays/timeouts when sending one-off RPCs rapdily. Can still run out of vsockets, but they clean up pretty quickly, so add logic to sleep a bit and retry if ENOBUFS is returned by connect(). --- diff --git a/open-vm-tools/lib/include/vmware/tools/guestrpc.h b/open-vm-tools/lib/include/vmware/tools/guestrpc.h index 2fecfdfd9..b10972962 100644 --- a/open-vm-tools/lib/include/vmware/tools/guestrpc.h +++ b/open-vm-tools/lib/include/vmware/tools/guestrpc.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2008,2014-2016,2018-2019 VMware, Inc. All rights reserved. + * Copyright (C) 2008,2014-2016,2018-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -231,7 +231,7 @@ RpcChannel_New(void); #if defined(__linux__) || defined(_WIN32) RpcChannel * -VSockChannel_New(void); +VSockChannel_New(int flags); #endif void diff --git a/open-vm-tools/lib/rpcChannel/rpcChannel.c b/open-vm-tools/lib/rpcChannel/rpcChannel.c index b7c2c083c..c1cc9e847 100644 --- a/open-vm-tools/lib/rpcChannel/rpcChannel.c +++ b/open-vm-tools/lib/rpcChannel/rpcChannel.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2008-2016,2018-2019 VMware, Inc. All rights reserved. + * Copyright (C) 2008-2016,2018-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -808,19 +808,19 @@ RpcChannel_SetBackdoorOnly(void) /** - * Create an RpcChannel instance using a prefered channel implementation, + * Create a one-off RpcChannel instance using a prefered channel implementation, * currently this is VSockChannel. * * @return RpcChannel */ -RpcChannel * -RpcChannel_New(void) +static RpcChannel * +RpcChannel_NewOne(int flags) { RpcChannel *chan; #if (defined(__linux__) && !defined(USERWORLD)) || defined(_WIN32) chan = (gUseBackdoorOnly || gVSocketFailed) ? - BackdoorChannel_New() : VSockChannel_New(); + BackdoorChannel_New() : VSockChannel_New(flags); #else chan = BackdoorChannel_New(); #endif @@ -828,6 +828,20 @@ RpcChannel_New(void) } +/** + * Create an RpcChannel instance using a prefered channel implementation, + * currently this is VSockChannel. + * + * @return RpcChannel + */ + +RpcChannel * +RpcChannel_New(void) +{ + return RpcChannel_NewOne(0); +} + + /** * Start an RPC channel. We may fallback to backdoor channel when other type * of channel fails to start. @@ -1068,11 +1082,14 @@ RpcChannelSendOneRaw(const char *data, { RpcChannel *chan; gboolean status = FALSE; + int flags; + flags = RPCCHANNEL_FLAGS_SEND_ONE; #if (defined(__linux__) && !defined(USERWORLD)) || defined(_WIN32) - chan = priv ? VSockChannel_New() : RpcChannel_New(); + flags |= RPCCHANNEL_FLAGS_FAST_CLOSE; + chan = priv ? VSockChannel_New(flags) : RpcChannel_NewOne(flags); #else - chan = RpcChannel_New(); + chan = RpcChannel_NewOne(flags); #endif if (chan == NULL) { diff --git a/open-vm-tools/lib/rpcChannel/rpcChannelInt.h b/open-vm-tools/lib/rpcChannel/rpcChannelInt.h index 6584fc21f..00b2e24d9 100644 --- a/open-vm-tools/lib/rpcChannel/rpcChannelInt.h +++ b/open-vm-tools/lib/rpcChannel/rpcChannelInt.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2008-2016,2018-2019 VMware, Inc. All rights reserved. + * Copyright (C) 2008-2016,2018-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -41,6 +41,15 @@ struct RpcIn; #endif +/* + * Flags associated with the RPC Channel + */ + +/* Channel will be usaed for a single RPC */ +#define RPCCHANNEL_FLAGS_SEND_ONE 0x1 +/* VMX should close channel after sending reply */ +#define RPCCHANNEL_FLAGS_FAST_CLOSE 0x2 + /** a list of interface functions for a channel implementation */ typedef struct _RpcChannelFuncs{ gboolean (*start)(RpcChannel *); diff --git a/open-vm-tools/lib/rpcChannel/simpleSocket.c b/open-vm-tools/lib/rpcChannel/simpleSocket.c index 9af19ea97..e38e14d72 100644 --- a/open-vm-tools/lib/rpcChannel/simpleSocket.c +++ b/open-vm-tools/lib/rpcChannel/simpleSocket.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2013-2017,2019 VMware, Inc. All rights reserved. + * Copyright (C) 2013-2017,2019-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -376,6 +376,8 @@ Socket_ConnectVMCI(unsigned int cid, // IN /* We are required to use a privileged source port. */ localPort = PRIVILEGED_PORT_MAX; while (localPort >= PRIVILEGED_PORT_MIN) { + int retryCount = 0; + fd = SocketConnectVmciInternal(&addr, localPort, &apiErr, &sysErr); if (fd != INVALID_SOCKET) { goto done; @@ -400,6 +402,23 @@ Socket_ConnectVMCI(unsigned int cid, // IN */ continue; } + + if (apiErr == SOCKERR_CONNECT && sysErr == SYSERR_ENOBUFS) { + /* + * ENOBUFS can happen if we're out of vsocks in the kernel. + * Delay a bit and try again using the same port. + * Have a retry count in case something has gone horribly wrong. + */ + if (++retryCount > 5) { + goto done; + } +#ifdef _WIN32 + Sleep(1); +#else + usleep(1000); +#endif + continue; + } /* Unrecoverable error occurred */ goto done; } @@ -508,6 +527,7 @@ error: static gboolean Socket_PackSendData(const char *buf, // IN int len, // IN + Bool fastClose, // IN char **serBuf, // OUT int32 *serBufLen) // OUT { @@ -542,6 +562,13 @@ Socket_PackSendData(const char *buf, // IN goto error; } + if (fastClose) { + res = DataMap_SetInt64(&map, GUESTRPCPKT_FIELD_FAST_CLOSE, TRUE, TRUE); + if (res != DMERR_SUCCESS) { + goto error; + } + } + res = DataMap_Serialize(&map, serBuf, serBufLen); if (res != DMERR_SUCCESS) { goto error; @@ -642,13 +669,15 @@ Socket_RecvPacket(SOCKET sock, // IN gboolean Socket_SendPacket(SOCKET sock, // IN const char *payload, // IN - int payloadLen) // IN + int payloadLen, // IN + Bool fastClose) // IN { gboolean ok; char *sendBuf; int sendBufLen; - if (!Socket_PackSendData(payload, payloadLen, &sendBuf, &sendBufLen)) { + if (!Socket_PackSendData(payload, payloadLen, fastClose, + &sendBuf, &sendBufLen)) { return FALSE; } diff --git a/open-vm-tools/lib/rpcChannel/simpleSocket.h b/open-vm-tools/lib/rpcChannel/simpleSocket.h index a715aefbd..a7ed738c7 100644 --- a/open-vm-tools/lib/rpcChannel/simpleSocket.h +++ b/open-vm-tools/lib/rpcChannel/simpleSocket.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2013-2016 VMware, Inc. All rights reserved. + * Copyright (C) 2013-2016,2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -53,6 +53,7 @@ typedef enum { #define SYSERR_EACCESS WSAEACCES #define SYSERR_EINTR WSAEINTR #define SYSERR_ECONNRESET WSAECONNRESET +#define SYSERR_ENOBUFS WSAENOBUFS typedef int socklen_t; @@ -62,6 +63,7 @@ typedef int socklen_t; #define SYSERR_EACCESS EACCES #define SYSERR_EINTR EINTR #define SYSERR_ECONNRESET ECONNRESET +#define SYSERR_ENOBUFS ENOBUFS typedef int SOCKET; #define SOCKET_ERROR (-1) @@ -89,6 +91,7 @@ gboolean Socket_RecvPacket(SOCKET sock, int *payloadLen); gboolean Socket_SendPacket(SOCKET sock, const char *payload, - int payloadLen); + int payloadLen, + Bool fastClose); #endif /* _SIMPLESOCKET_H_ */ diff --git a/open-vm-tools/lib/rpcChannel/vsockChannel.c b/open-vm-tools/lib/rpcChannel/vsockChannel.c index db2eb737e..089819042 100644 --- a/open-vm-tools/lib/rpcChannel/vsockChannel.c +++ b/open-vm-tools/lib/rpcChannel/vsockChannel.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2013-2016,2018-2019 VMware, Inc. All rights reserved. + * Copyright (C) 2013-2016,2018-2020 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -38,6 +38,7 @@ typedef struct VSockOut { char *payload; int payloadLen; RpcChannelType type; + int flags; } VSockOut; typedef struct VSockChannel { @@ -116,13 +117,14 @@ VSockCreateConn(gboolean *isPriv) // OUT */ static VSockOut * -VSockOutConstruct(void) +VSockOutConstruct(int flags) { VSockOut *out = calloc(1, sizeof *out); if (out != NULL) { out->fd = INVALID_SOCKET; out->type = RPCCHANNEL_TYPE_INACTIVE; + out->flags = flags; } return out; } @@ -260,7 +262,8 @@ VSockOutSend(VSockOut *out, // IN Debug(LGPFX "Sending request for conn %d, reqLen=%d\n", out->fd, (int)reqLen); - if (!Socket_SendPacket(out->fd, request, reqLen)) { + if (!Socket_SendPacket(out->fd, request, reqLen, + (out->flags & RPCCHANNEL_FLAGS_FAST_CLOSE))) { *reply = "VSockOut: Unable to send data for the RPCI command"; goto error; } @@ -559,7 +562,7 @@ VSockChannelStopRpcOut(RpcChannel *chan) */ RpcChannel * -VSockChannel_New(void) +VSockChannel_New(int flags) { RpcChannel *chan; VSockChannel *vsock; @@ -578,7 +581,7 @@ VSockChannel_New(void) chan = RpcChannel_Create(); vsock = g_malloc0(sizeof *vsock); - vsock->out = VSockOutConstruct(); + vsock->out = VSockOutConstruct(flags); ASSERT(vsock->out != NULL); #if defined(NEED_RPCIN)