From: VMware, Inc <> Date: Thu, 17 Dec 2009 23:00:31 +0000 (-0800) Subject: Modify the linux vsock code to work with VMADDR_CID_ANY X-Git-Tag: 2009.12.16-217847~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c3f0d6f8a48d7af9de532d90bdd0d94603eae043;p=thirdparty%2Fopen-vm-tools.git Modify the linux vsock code to work with VMADDR_CID_ANY 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 --- diff --git a/open-vm-tools/modules/linux/vsock/linux/af_vsock.c b/open-vm-tools/modules/linux/vsock/linux/af_vsock.c index b620adf64..a1853af77 100644 --- a/open-vm-tools/modules/linux/vsock/linux/af_vsock.c +++ b/open-vm-tools/modules/linux/vsock/linux/af_vsock.c @@ -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(®istrationMutex); - - 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(®istrationMutex); -} - - /* *---------------------------------------------------------------------------- * @@ -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); diff --git a/open-vm-tools/modules/linux/vsock/linux/util.c b/open-vm-tools/modules/linux/vsock/linux/util.c index 5c08f2037..0d956cc96 100644 --- a/open-vm-tools/modules/linux/vsock/linux/util.c +++ b/open-vm-tools/modules/linux/vsock/linux/util.c @@ -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. */ diff --git a/open-vm-tools/modules/linux/vsock/linux/vsockAddr.c b/open-vm-tools/modules/linux/vsock/linux/vsockAddr.c index cbdc00b64..7dfcefd2d 100644 --- a/open-vm-tools/modules/linux/vsock/linux/vsockAddr.c +++ b/open-vm-tools/modules/linux/vsock/linux/vsockAddr.c @@ -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; +} + + /* *---------------------------------------------------------------------------- * diff --git a/open-vm-tools/modules/linux/vsock/linux/vsockAddr.h b/open-vm-tools/modules/linux/vsock/linux/vsockAddr.h index a90ea31f2..defc733e6 100644 --- a/open-vm-tools/modules/linux/vsock/linux/vsockAddr.h +++ b/open-vm-tools/modules/linux/vsock/linux/vsockAddr.h @@ -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, diff --git a/open-vm-tools/modules/linux/vsock/linux/vsockPacket.h b/open-vm-tools/modules/linux/vsock/linux/vsockPacket.h index 3e6f23da9..21badd9cc 100644 --- a/open-vm-tools/modules/linux/vsock/linux/vsockPacket.h +++ b/open-vm-tools/modules/linux/vsock/linux/vsockPacket.h @@ -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;