]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Modify the linux vsock code to work with VMADDR_CID_ANY
authorVMware, Inc <>
Thu, 17 Dec 2009 23:00:31 +0000 (15:00 -0800)
committerMarcelo Vanzin <mvanzin@vmware.com>
Thu, 17 Dec 2009 23:00:31 +0000 (15:00 -0800)
Previous to this change VMADDR_CID_ANY was directly mapped to a context id when it was recv'd from
userland. Change this behavior to store VMADDR_CID_ANY and to register datagram handlers as
any cid for:
1. The stream control channel under all conditions.
2. The datagram handler if it is being bound to VMADDR_CID_ANY.

Signed-off-by: Marcelo Vanzin <mvanzin@vmware.com>
open-vm-tools/modules/linux/vsock/linux/af_vsock.c
open-vm-tools/modules/linux/vsock/linux/util.c
open-vm-tools/modules/linux/vsock/linux/vsockAddr.c
open-vm-tools/modules/linux/vsock/linux/vsockAddr.h
open-vm-tools/modules/linux/vsock/linux/vsockPacket.h

index b620adf64c3e253a1bfa8425f31bb7f3d3487a85..a1853af77b6db4c1cabedcc65627af0e66db9ec1 100644 (file)
@@ -351,7 +351,6 @@ static Bool vmciDevicePresent = FALSE;
 #endif
 static VMCIHandle vmciStreamHandle = { VMCI_INVALID_ID, VMCI_INVALID_ID };
 static VMCIId qpResumedSubId = VMCI_INVALID_ID;
-static VMCIId ctxChangedSubId = VMCI_INVALID_ID;
 
 static int PROTOCOL_OVERRIDE = -1;
 
@@ -1268,52 +1267,6 @@ VSockVmciQPResumedCB(VMCIId subId,             // IN
 }
 
 
-/*
- *----------------------------------------------------------------------------
- *
- * VSockVmciCidChangedCB --
- *
- *    Invoked when the context id of the VM may have changed. In this case
- *    we need to reregister the stream control channel handler.
- *
- *    XXX: Open stream sockets will be closed by the detached callback for the
- *    QP. However, this doesn't fix up bound stream sockets. We should figure
- *    out what the right thing to do is in that case.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-static void
-VSockVmciCidChangedCB(VMCIId subId,             // IN
-                      VMCI_EventData *eData,    // IN
-                      void *clientData)         // IN
-{
-   int err;
-   compat_mutex_lock(&registrationMutex);
-
-   if (!VMCI_HANDLE_INVALID(vmciStreamHandle)) {
-      VMCIDatagram_DestroyHnd(vmciStreamHandle);
-      vmciStreamHandle = VMCI_INVALID_HANDLE;
-   }
-
-   err = VSockVmciDatagramCreateHnd(VSOCK_PACKET_RID, 0,
-                                    VSockVmciRecvStreamCB, NULL,
-                                    &vmciStreamHandle,
-                                    TRUE);
-   if (err < 0) {
-      Warning("Unable to create datagram handle. (%d)\n", err);
-   }
-
-   compat_mutex_unlock(&registrationMutex);
-}
-
-
 /*
  *----------------------------------------------------------------------------
  *
@@ -1779,6 +1732,11 @@ VSockVmciRecvConnectingServer(struct sock *listener, // IN: the listening socket
 
    /* Now attach to the queue pair the client created. */
    handle = pkt->u.handle;
+
+   /*
+    * vpending->localAddr always has a context id so we do not
+    * need to worry about VMADDR_CID_ANY in this case.
+    */
    isLocal = vpending->remoteAddr.svm_cid == vpending->localAddr.svm_cid;
    flags = VMCI_QPFLAG_ATTACH_ONLY;
    flags |= isLocal ? VMCI_QPFLAG_LOCAL : 0;
@@ -1921,6 +1879,7 @@ VSockVmciRecvConnectingClient(struct sock *sk,       // IN: socket
           vsk->detachSubId != VMCI_INVALID_ID) {
          skerr = EPROTO;
          err = -EINVAL;
+
          goto destroy;
       }
 
@@ -2549,10 +2508,10 @@ __VSockVmciBind(struct sock *sk,          // IN/OUT
       return -EADDRNOTAVAIL;
    }
 
-   newAddr.svm_cid = cid;
+   newAddr.svm_cid = addr->svm_cid;
 
    switch (sk->compat_sk_socket->type) {
-   case SOCK_STREAM:
+   case SOCK_STREAM: {
       spin_lock_bh(&vsockTableLock);
 
       if (addr->svm_port == VMADDR_PORT_ANY) {
@@ -2592,7 +2551,10 @@ __VSockVmciBind(struct sock *sk,          // IN/OUT
 
       }
       break;
-   case SOCK_DGRAM:
+   }
+   case SOCK_DGRAM: {
+      uint32 flags = 0;
+
       /* VMCI will select a resource ID for us if we provide VMCI_INVALID_ID. */
       newAddr.svm_port = addr->svm_port == VMADDR_PORT_ANY ?
                             VMCI_INVALID_ID :
@@ -2604,12 +2566,15 @@ __VSockVmciBind(struct sock *sk,          // IN/OUT
          goto out;
       }
 
-      err = VSockVmciDatagramCreateHnd(newAddr.svm_port, 0,
+      if (newAddr.svm_cid == VMADDR_CID_ANY) {
+         flags = VMCI_FLAG_ANYCID_DG_HND;
+      }
+
+      err = VSockVmciDatagramCreateHnd(newAddr.svm_port, flags,
                                        VSockVmciRecvDgramCB, sk,
                                        &vsk->dgHandle,
                                        vsk->trusted);
       if (err != VMCI_SUCCESS ||
-          vsk->dgHandle.context == VMCI_INVALID_ID ||
           vsk->dgHandle.resource == VMCI_INVALID_ID) {
          err = VSockVmci_ErrorToVSockError(err);
          goto out;
@@ -2617,11 +2582,12 @@ __VSockVmciBind(struct sock *sk,          // IN/OUT
 
       newAddr.svm_port = VMCI_HANDLE_TO_RESOURCE_ID(vsk->dgHandle);
       break;
-   default:
+   }
+   default: {
       err = -EINVAL;
       goto out;
    }
-
+   }
    /*
     * VSockVmci_GetAFValue() acquires a mutex and may sleep, so fill the
     * field after unlocking socket tables.
@@ -3060,32 +3026,17 @@ VSockVmciRegisterAddressFamily(void)
    }
 #endif
 
-   /*
-    * Register the context id changed callback before creating our datagram
-    * handler to make sure we don't miss a context id change.
-    */
-   err = VMCIEvent_Subscribe(VMCI_EVENT_CTX_ID_UPDATE,
-                             VMCI_FLAG_EVENT_DELAYED_CB,
-                             VSockVmciCidChangedCB,
-                             NULL,
-                             &ctxChangedSubId);
-   if (err < VMCI_SUCCESS) {
-      Warning("Unable to subscribe to Ctx Id update event. (%d)\n", err);
-      err = VSockVmci_ErrorToVSockError(err);
-      ctxChangedSubId = VMCI_INVALID_ID;
-      return VSockVmci_ErrorToVSockError(err);
-   }
-
    /*
     * Create the datagram handle that we will use to send and receive all
     * VSocket control messages for this context.
     */
-    err = VSockVmciDatagramCreateHnd(VSOCK_PACKET_RID, 0,
+    err = VSockVmciDatagramCreateHnd(VSOCK_PACKET_RID,
+                                     VMCI_FLAG_ANYCID_DG_HND,
                                      VSockVmciRecvStreamCB, NULL,
                                      &vmciStreamHandle,
                                      TRUE);
    if (err < 0 ||
-       vmciStreamHandle.context == VMCI_INVALID_ID ||
+       vmciStreamHandle.context != VMCI_INVALID_ID ||
        vmciStreamHandle.resource == VMCI_INVALID_ID) {
       Warning("Unable to create datagram handle. (%d)\n", err);
       goto error;
@@ -3134,10 +3085,6 @@ VSockVmciRegisterAddressFamily(void)
    return vsockVmciFamilyOps.family;
 
 error:
-   if (ctxChangedSubId != VMCI_INVALID_ID) {
-      VMCIEvent_Unsubscribe(ctxChangedSubId);
-      ctxChangedSubId = VMCI_INVALID_ID;
-   }
    if (qpResumedSubId != VMCI_INVALID_ID) {
       VMCIEvent_Unsubscribe(qpResumedSubId);
       qpResumedSubId = VMCI_INVALID_ID;
@@ -3178,11 +3125,6 @@ VSockVmciUnregisterAddressFamily(void)
    }
 #endif
 
-   if (ctxChangedSubId != VMCI_INVALID_ID) {
-      VMCIEvent_Unsubscribe(ctxChangedSubId);
-      ctxChangedSubId = VMCI_INVALID_ID;
-   }
-
    if (!VMCI_HANDLE_INVALID(vmciStreamHandle)) {
       if (VMCIDatagram_DestroyHnd(vmciStreamHandle) != VMCI_SUCCESS) {
          Warning("Could not destroy VMCI datagram handle.\n");
@@ -3440,7 +3382,6 @@ VSockVmciStreamConnect(struct socket *sock,   // IN
    lock_sock(sk);
 
    /* XXX AF_UNSPEC should make us disconnect like AF_INET. */
-
    switch (sock->state) {
    case SS_CONNECTED:
       err = -EISCONN;
@@ -3485,6 +3426,14 @@ VSockVmciStreamConnect(struct socket *sock,   // IN
          }
       }
 
+      /*
+       * For the client stream sockets, we always want to make sure that
+       * we have a specific context id.
+       */
+      if (vsk->localAddr.svm_cid == VMADDR_CID_ANY) {
+         vsk->localAddr.svm_cid = VMCI_GetContextID();
+      }
+
       sk->compat_sk_state = SS_CONNECTING;
 
       if (VSockVmciOldProtoOverride(&oldPktProto) && oldPktProto) {
@@ -4102,6 +4051,7 @@ VSockVmciDgramSendmsg(struct kiocb *kiocb,          // UNUSED
 
    dg->dst = VMCI_MAKE_HANDLE(remoteAddr->svm_cid, remoteAddr->svm_port);
    dg->src = VMCI_MAKE_HANDLE(vsk->localAddr.svm_cid, vsk->localAddr.svm_port);
+
    dg->payloadSize = len;
 
    err = VMCIDatagram_Send(dg);
index 5c08f20379a3e8194a7998e6da6675a994dfaa7c..0d956cc9642ba6a4b21dc482baebd93b54b71a57 100644 (file)
@@ -367,7 +367,7 @@ __VSockVmciFindBoundSocket(struct sockaddr_vm *addr)  // IN
 
 
    list_for_each_entry(vsk, vsockBoundSockets(addr), boundTable) {
-      if (VSockAddr_EqualsAddr(addr, &vsk->localAddr)) {
+      if (VSockAddr_EqualsAddrAny(addr, &vsk->localAddr)) {
          sk = sk_vsock(vsk);
 
          /* We only store stream sockets in the bound table. */
index cbdc00b649fc9d82fe3088e8a7c385d608ab4477..7dfcefd2d86aab907bd1a39776ce8bb552df7d77 100644 (file)
@@ -221,7 +221,7 @@ Bool
 VSockAddr_Bound(struct sockaddr_vm *addr) // IN: socket address to check
 {
    ASSERT(addr);
-   return addr->svm_cid != VMADDR_CID_ANY && addr->svm_port != VMADDR_PORT_ANY;
+   return addr->svm_port != VMADDR_PORT_ANY;
 }
 
 
@@ -280,6 +280,39 @@ VSockAddr_EqualsAddr(struct sockaddr_vm *addr,  // IN
 }
 
 
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockAddr_EqualsAddrAny --
+ *
+ *    Determine if the given addresses are equal. Will accept either an exact
+ *    match or one where the rids match and that either the cids match or
+ *    are set to VMADDR_CID_ANY.
+ *
+ * Results:
+ *    TRUE if the addresses are equal, FALSE otherwise.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+VSockAddr_EqualsAddrAny(struct sockaddr_vm *addr,  // IN
+                        struct sockaddr_vm *other) // IN
+{
+   VSOCK_ADDR_NOFAMILY_ASSERT(addr);
+   VSOCK_ADDR_NOFAMILY_ASSERT(other);
+   if (addr->svm_cid == VMADDR_CID_ANY ||
+       other->svm_cid == VMADDR_CID_ANY ||
+       addr->svm_cid == other->svm_cid) {
+      return (addr->svm_port == other->svm_port);
+   }
+   return FALSE;
+}
+
+
 /*
  *----------------------------------------------------------------------------
  *
index a90ea31f2b3a77cde7e78e3880fb3b51afbe6c3b..defc733e668a1b7e229d1294888e0537dda63ca6 100644 (file)
@@ -41,6 +41,7 @@ int32 VSockAddr_ValidateNoFamily(const struct sockaddr_vm *addr);
 Bool VSockAddr_Bound(struct sockaddr_vm *addr);
 void VSockAddr_Unbind(struct sockaddr_vm *addr);
 Bool VSockAddr_EqualsAddr(struct sockaddr_vm *addr, struct sockaddr_vm *other);
+Bool VSockAddr_EqualsAddrAny(struct sockaddr_vm *addr, struct sockaddr_vm *other);
 Bool VSockAddr_EqualsHandlePort(struct sockaddr_vm *addr, VMCIHandle handle,
                                 uint32 port);
 int32 VSockAddr_Cast(const struct sockaddr *addr, int32 len,
index 3e6f23da91cd39545138f5f9cf2cebbeb5956c6a..21badd9cc44a4cf4299fd9782037ef63ffcbf301 100644 (file)
@@ -146,7 +146,11 @@ VSockPacket_Init(VSockPacket *pkt,        // OUT
    VSOCK_ADDR_NOFAMILY_ASSERT(src);
    VSOCK_ADDR_NOFAMILY_ASSERT(dst);
 
-   pkt->dg.src = VMCI_MAKE_HANDLE(src->svm_cid, VSOCK_PACKET_RID);
+   /*
+    * We register the stream control handler as an any cid handle so we
+    * must always send from a source address of VMADDR_CID_ANY
+    */
+   pkt->dg.src = VMCI_MAKE_HANDLE(VMADDR_CID_ANY, VSOCK_PACKET_RID);
    pkt->dg.dst = VMCI_MAKE_HANDLE(dst->svm_cid, VSOCK_PACKET_RID);
    pkt->dg.payloadSize = sizeof *pkt - sizeof pkt->dg;
    pkt->version = VSOCK_PACKET_VERSION;