]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Send GUESTRPCPKT_FIELD_FAST_CLOSE when doing one-off RPC via vsock
authorOliver Kurth <okurth@vmware.com>
Wed, 4 Mar 2020 20:07:13 +0000 (12:07 -0800)
committerOliver Kurth <okurth@vmware.com>
Wed, 4 Mar 2020 20:07:13 +0000 (12:07 -0800)
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().

open-vm-tools/lib/include/vmware/tools/guestrpc.h
open-vm-tools/lib/rpcChannel/rpcChannel.c
open-vm-tools/lib/rpcChannel/rpcChannelInt.h
open-vm-tools/lib/rpcChannel/simpleSocket.c
open-vm-tools/lib/rpcChannel/simpleSocket.h
open-vm-tools/lib/rpcChannel/vsockChannel.c

index 2fecfdfd90bb8f495ed17b6bf8db45a17e2c1db4..b10972962402ca1f2eef4e42aab5a5e0748eb021 100644 (file)
@@ -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
index b7c2c083c4deee4de74f2bd7710476163127a2c3..c1cc9e8479e63176a0a62cb717482d80744c4e4a 100644 (file)
@@ -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) {
index 6584fc21f54c34a56d18e21040304ca355130385..00b2e24d927357b97fcf99536ec6003cd9b79a8d 100644 (file)
@@ -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
 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 *);
index 9af19ea9741356692d7a85ef61bdce769908f8af..e38e14d725791183f2612172ce57257ae35a2f48 100644 (file)
@@ -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;
    }
 
index a715aefbdc02fe9ca902a8bb3bde19f55bcda3eb..a7ed738c78dc54f5058600cd2470b2ee23a54a06 100644 (file)
@@ -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_ */
index db2eb737eef47aea4437e79eb5dc424e9403a82b..0898190420ba1752594bed7c3d25e7800c97d811 100644 (file)
@@ -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)