64
65
#define HASH_TABLE_SIZE 64
67
#define VMCI_HASHRESOURCE(handle, size) \
68
VMCI_HashId(VMCI_HANDLE_TO_RESOURCE_ID(handle), (size))
67
71
* Hash table containing all the datagram handles for this VM. It is
68
72
* synchronized using a single lock but we should consider making it more
72
76
typedef struct DatagramHashTable {
74
78
DatagramHashEntry *entries[HASH_TABLE_SIZE];
81
typedef struct VMCIDelayedDatagramInfo {
82
DatagramHashEntry *entry;
84
} VMCIDelayedDatagramInfo;
78
87
static int DatagramReleaseCB(void *clientData);
79
88
static int DatagramHashAddEntry(DatagramHashEntry *entry, VMCIId contextID);
80
89
static int DatagramHashRemoveEntry(VMCIHandle handle);
81
90
static DatagramHashEntry *DatagramHashGetEntry(VMCIHandle handle);
91
static DatagramHashEntry *DatagramHashGetEntryAnyCid(VMCIHandle handle);
82
92
static void DatagramHashReleaseEntry(DatagramHashEntry *entry);
83
static Bool DatagramHandleUniqueLocked(VMCIHandle handle);
93
static Bool DatagramHandleUniqueLockedAnyCid(VMCIHandle handle);
84
94
static int DatagramProcessNotify(void *clientData, VMCIDatagram *msg);
86
96
DatagramHashTable hashTable;
133
143
VMCILockFlags flags;
134
144
static VMCIId datagramRID = VMCI_RESERVED_RESOURCE_ID_MAX + 1;
136
ASSERT(entry && contextID != VMCI_INVALID_ID);
138
148
VMCI_GrabLock_BH(&hashTable.lock, &flags);
139
149
if (!VMCI_HANDLE_INVALID(entry->handle) &&
140
!DatagramHandleUniqueLocked(entry->handle)) {
150
!DatagramHandleUniqueLockedAnyCid(entry->handle)) {
141
151
VMCI_ReleaseLock_BH(&hashTable.lock, flags);
142
152
return VMCI_ERROR_DUPLICATE_ENTRY;
143
153
} else if (VMCI_HANDLE_INVALID(entry->handle)) {
152
162
ASSERT(oldRID > VMCI_RESERVED_RESOURCE_ID_MAX);
154
164
handle = VMCI_MAKE_HANDLE(contextID, datagramRID);
155
foundRID = DatagramHandleUniqueLocked(handle);
165
foundRID = DatagramHandleUniqueLockedAnyCid(handle);
157
167
if (UNLIKELY(!datagramRID)) {
177
187
ASSERT(!VMCI_HANDLE_INVALID(entry->handle));
178
idx = VMCI_Hash(entry->handle, HASH_TABLE_SIZE);
188
idx = VMCI_HASHRESOURCE(entry->handle, HASH_TABLE_SIZE);
180
190
/* New entry is added to top/front of hash bucket. */
181
191
entry->refCount++;
204
214
int result = VMCI_ERROR_NOT_FOUND;
205
215
VMCILockFlags flags;
206
216
DatagramHashEntry *prev, *cur;
207
int idx = VMCI_Hash(handle, HASH_TABLE_SIZE);
217
int idx = VMCI_HASHRESOURCE(handle, HASH_TABLE_SIZE);
210
220
VMCI_GrabLock_BH(&hashTable.lock, &flags);
246
256
* DatagramHashGetEntry --
258
* Gets the given datagram hashtable entry based on handle lookup.
261
* Datagram hash entry if found. NULL otherwise.
251
263
*-------------------------------------------------------------------------
254
266
static DatagramHashEntry *
255
DatagramHashGetEntry(VMCIHandle handle)
267
DatagramHashGetEntry(VMCIHandle handle) // IN
257
269
VMCILockFlags flags;
258
270
DatagramHashEntry *cur;
259
int idx = VMCI_Hash(handle, HASH_TABLE_SIZE);
271
int idx = VMCI_HASHRESOURCE(handle, HASH_TABLE_SIZE);
261
273
VMCI_GrabLock_BH(&hashTable.lock, &flags);
262
275
for (cur = hashTable.entries[idx]; cur != NULL; cur = cur->next) {
263
276
if (VMCI_HANDLE_EQUAL(cur->handle, handle)) {
268
VMCI_ReleaseLock_BH(&hashTable.lock, flags);
282
VMCI_ReleaseLock_BH(&hashTable.lock, flags);
289
*-------------------------------------------------------------------------
291
* DatagramHashGetEntryAnyCid --
293
* Gets the given datagram hashtable entry based on handle lookup.
294
* Will match "any" or specific cid.
297
* Datagram hash entry if found. NULL otherwise.
299
*-------------------------------------------------------------------------
302
static DatagramHashEntry *
303
DatagramHashGetEntryAnyCid(VMCIHandle handle) // IN
306
DatagramHashEntry *cur;
307
int idx = VMCI_HASHRESOURCE(handle, HASH_TABLE_SIZE);
309
VMCI_GrabLock_BH(&hashTable.lock, &flags);
311
for (cur = hashTable.entries[idx]; cur != NULL; cur = cur->next) {
312
if (VMCI_HANDLE_TO_RESOURCE_ID(cur->handle) ==
313
VMCI_HANDLE_TO_RESOURCE_ID(handle)) {
314
if (VMCI_HANDLE_TO_CONTEXT_ID(cur->handle) == VMCI_INVALID_ID ||
315
VMCI_HANDLE_TO_CONTEXT_ID(cur->handle) ==
316
VMCI_HANDLE_TO_CONTEXT_ID(handle)) {
323
VMCI_ReleaseLock_BH(&hashTable.lock, flags);
277
332
* DatagramHashReleaseEntry --
334
* Drops a reference to the current hash entry. If this is the last
335
* reference then the entry is freed.
282
340
*-------------------------------------------------------------------------
286
DatagramHashReleaseEntry(DatagramHashEntry *entry)
344
DatagramHashReleaseEntry(DatagramHashEntry *entry) // IN
288
346
VMCILockFlags flags;
291
349
entry->refCount--;
293
351
/* Check if this is last reference and signal the destroy event if so. */
294
if (entry->refCount == 0) {
352
if (entry->refCount == 0) {
295
353
VMCI_SignalEvent(&entry->destroyEvent);
297
355
VMCI_ReleaseLock_BH(&hashTable.lock, flags);
302
360
*------------------------------------------------------------------------------
304
* DatagramHandleUniqueLocked --
362
* DatagramHandleUniqueLockedAnyCid --
306
* Checks whether the given handle is already in the hash
307
* table. Assumes that the caller to have the hash table lock.
364
* Checks whether the resource id (with any context id) is already in the
366
* Assumes that the caller has the hash table lock.
369
* TRUE if the handle is unique. FALSE otherwise.
312
371
*------------------------------------------------------------------------------
316
DatagramHandleUniqueLocked(VMCIHandle handle)
375
DatagramHandleUniqueLockedAnyCid(VMCIHandle handle) // IN
318
377
Bool unique = TRUE;
319
378
DatagramHashEntry *entry;
320
int idx = VMCI_Hash(handle, HASH_TABLE_SIZE);
379
int idx = VMCI_HASHRESOURCE(handle, HASH_TABLE_SIZE);
322
381
entry = hashTable.entries[idx];
324
if (VMCI_HANDLE_EQUAL(entry->handle, handle)) {
383
if (VMCI_HANDLE_TO_RESOURCE_ID(entry->handle) ==
384
VMCI_HANDLE_TO_RESOURCE_ID(handle)) {
359
419
DatagramHashEntry *entry;
360
420
VMCIHandle handle;
361
VMCIId contextID = VMCI_GetContextID();
363
423
if (!recvCB || !outHandle) {
364
424
return VMCI_ERROR_INVALID_ARGS;
367
/* Validate contextID. */
368
if (contextID == VMCI_INVALID_ID) {
369
return VMCI_ERROR_NO_RESOURCES;
427
if ((flags & VMCI_FLAG_ANYCID_DG_HND) != 0) {
428
contextID = VMCI_INVALID_ID;
430
contextID = VMCI_GetContextID();
431
/* Validate contextID. */
432
if (contextID == VMCI_INVALID_ID) {
433
return VMCI_ERROR_NO_RESOURCES;
372
438
if ((flags & VMCI_FLAG_WELLKNOWN_DG_HND) != 0) {
373
439
VMCIDatagramWellKnownMapMsg wkMsg;
374
440
if (resourceID == VMCI_INVALID_ID) {
375
return VMCI_ERROR_INVALID_ARGS;
441
return VMCI_ERROR_INVALID_ARGS;
377
443
wkMsg.hdr.dst.context = VMCI_HYPERVISOR_CONTEXT_ID;
378
444
wkMsg.hdr.dst.resource = VMCI_DATAGRAM_REQUEST_MAP;
381
447
wkMsg.wellKnownID = resourceID;
382
448
result = VMCI_SendDatagram((VMCIDatagram *)&wkMsg);
383
449
if (result < VMCI_SUCCESS) {
384
VMCI_LOG(("Failed to reserve wellknown id %d, error %d.\n",
385
resourceID, result));
450
VMCI_LOG(("Failed to reserve wellknown id %d, error %d.\n",
451
resourceID, result));
389
455
handle = VMCI_MAKE_HANDLE(VMCI_WELL_KNOWN_CONTEXT_ID, resourceID);
401
467
return VMCI_ERROR_NO_MEM;
470
if (!VMCI_CanScheduleDelayedWork()) {
471
if (flags & VMCI_FLAG_DG_DELAYED_CB) {
472
VMCI_FreeKernelMem(entry, sizeof *entry);
473
return VMCI_ERROR_INVALID_ARGS;
475
entry->runDelayed = FALSE;
477
entry->runDelayed = (flags & VMCI_FLAG_DG_DELAYED_CB) ? TRUE : FALSE;
404
480
entry->handle = handle;
405
481
entry->flags = flags;
406
482
entry->recvCB = recvCB;
640
717
/* Check srcHandle exists otherwise fail. */
641
718
entry = DatagramHashGetEntry(msg->src);
642
719
if (entry == NULL) {
643
VMCI_LOG(("Couldn't find handle 0x%x:0x%x.\n",
720
VMCI_LOG(("Couldn't find handle 0x%x:0x%x.\n",
644
721
msg->src.context, msg->src.resource));
645
722
return VMCI_ERROR_INVALID_ARGS;
725
contextId = VMCI_HANDLE_TO_CONTEXT_ID(msg->src);
727
if (contextId == VMCI_INVALID_ID) {
728
msg->src = VMCI_MAKE_HANDLE(VMCI_GetContextID(),
729
VMCI_HANDLE_TO_RESOURCE_ID(msg->src));
648
732
retval = VMCI_SendDatagram(msg);
649
733
DatagramHashReleaseEntry(entry);
656
740
*-----------------------------------------------------------------------------
742
* VMCIDatagramDelayedDispatchCB --
744
* Calls the specified callback in a delayed context.
752
*-----------------------------------------------------------------------------
756
VMCIDatagramDelayedDispatchCB(void *data) // IN
758
VMCIDelayedDatagramInfo *dgInfo = (VMCIDelayedDatagramInfo *)data;
762
dgInfo->entry->recvCB(dgInfo->entry->clientData, &dgInfo->msg);
764
DatagramHashReleaseEntry(dgInfo->entry);
765
VMCI_FreeKernelMem(dgInfo, sizeof *dgInfo + (size_t)dgInfo->msg.payloadSize);
770
*-----------------------------------------------------------------------------
658
772
* VMCIDatagram_Dispatch --
660
* Forwards the datagram corresponding entry's callback.
774
* Forwards the datagram to the corresponding entry's callback. This will
775
* defer the datagram if requested by the client, so that the callback
776
* is invoked in a delayed context.
663
779
* VMCI_SUCCESS on success, error code if not.
672
788
VMCIDatagram_Dispatch(VMCIId contextID, // IN: unused
673
VMCIDatagram *msg) // IN
789
VMCIDatagram *msg) // IN
791
int32 err = VMCI_SUCCESS;
675
792
DatagramHashEntry *entry;
679
entry = DatagramHashGetEntry(msg->dst);
796
entry = DatagramHashGetEntryAnyCid(msg->dst);
680
797
if (entry == NULL) {
681
VMCI_LOG(("destination handle 0x%x:0x%x doesn't exists.\n",
798
VMCI_LOG(("destination handle 0x%x:0x%x doesn't exist.\n",
682
799
msg->dst.context, msg->dst.resource));
683
800
return VMCI_ERROR_NO_HANDLE;
803
if (!entry->recvCB) {
804
VMCI_LOG(("no handle callback for handle 0x%x:0x%x payload of "
806
msg->dst.context, msg->dst.resource, msg->payloadSize));
810
if (entry->runDelayed) {
811
VMCIDelayedDatagramInfo *dgInfo;
813
dgInfo = VMCI_AllocKernelMem(sizeof *dgInfo + (size_t)msg->payloadSize,
814
VMCI_MEMORY_ATOMIC | VMCI_MEMORY_NONPAGED);
815
if (NULL == dgInfo) {
816
err = VMCI_ERROR_NO_MEM;
820
dgInfo->entry = entry;
821
memcpy(&dgInfo->msg, msg, VMCI_DG_SIZE(msg));
823
err = VMCI_ScheduleDelayedWork(VMCIDatagramDelayedDispatchCB, dgInfo);
824
if (VMCI_SUCCESS == err) {
828
VMCI_FreeKernelMem(dgInfo, sizeof *dgInfo + (size_t)msg->payloadSize);
687
830
entry->recvCB(entry->clientData, msg);
689
VMCI_LOG(("no handle callback for handle 0x%x:0x%x payload of "
691
msg->dst.context, msg->dst.resource, msg->payloadSize));
693
834
DatagramHashReleaseEntry(entry);
855
VMCIDatagramProcess_Create(VMCIDatagramProcess **outDgmProc, // OUT:
856
VMCIDatagramCreateInfo *createInfo, // IN:
857
uintptr_t eventHnd) // IN:
995
VMCIDatagramProcess_Create(VMCIDatagramProcess **outDgmProc, // OUT:
996
VMCIDatagramCreateProcessInfo *createInfo, // IN:
997
uintptr_t eventHnd) // IN:
859
999
VMCIDatagramProcess *dgmProc;
879
1019
createInfo->result = VMCIDatagram_CreateHnd(createInfo->resourceID,
881
DatagramProcessNotify,
1021
DatagramProcessNotify,
884
1024
if (createInfo->result < VMCI_SUCCESS) {
885
1025
VMCI_FreeKernelMem(dgmProc, sizeof *dgmProc);
886
1026
return createInfo->result;