Changeset 28623 in vbox
- Timestamp:
- Apr 23, 2010 12:34:14 AM (15 years ago)
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/intnet.h
r28208 r28623 366 366 /** Only for the trunk (host/wire). */ 367 367 INTNETSWDECISION_TRUNK, 368 /** Used internally to indicate that the packet cannot be handled in the 369 * current context. */ 370 INTNETSWDECISION_BAD_CONTEXT, 371 /** Used internally to indicate that the packet should be dropped. */ 372 INTNETSWDECISION_DROP, 368 373 /** The usual 32-bit type expansion. */ 369 374 INTNETSWDECISION_32BIT_HACK = 0x7fffffff … … 721 726 722 727 /** The UUID for the (current) trunk factory. (case sensitive) */ 723 #define INTNETTRUNKFACTORY_UUID_STR " b010afb2-cb4c-44b7-9da9-1e113cfcd47c"728 #define INTNETTRUNKFACTORY_UUID_STR "daeaf07b-9974-48be-843e-b9afd763c2ff" 724 729 725 730 /** @name INTNETTRUNKFACTORY::pfnCreateAndConnect flags. -
trunk/src/VBox/Devices/Network/SrvIntNetR0.cpp
r28488 r28623 31 31 #include <VBox/pdm.h> 32 32 #include <VBox/log.h> 33 33 34 #include <iprt/asm.h> 34 #include <iprt/alloc.h> 35 #include <iprt/assert.h> 36 #include <iprt/handletable.h> 37 #include <iprt/mp.h> 38 #include <iprt/mem.h> 39 #include <iprt/net.h> 35 40 #include <iprt/semaphore.h> 36 41 #include <iprt/spinlock.h> 42 #include <iprt/string.h> 37 43 #include <iprt/thread.h> 38 #include <iprt/assert.h>39 #include <iprt/string.h>40 44 #include <iprt/time.h> 41 #include <iprt/handletable.h>42 #include <iprt/net.h>43 45 44 46 … … 50 52 #define INTNET_WITH_DHCP_SNOOPING 51 53 54 /** The maximum number of interface in a network. */ 55 #define INTNET_MAX_IFS (1023 + 1 + 16) 56 57 /** The number of entries to grow the destination tables with. */ 52 58 #if 0 53 /** Enables the new code - temporarily while doing the rewrite. */ 54 # define WITH_NEW_STUFF 59 # define INTNET_GROW_DSTTAB_SIZE 16 60 #else 61 # define INTNET_GROW_DSTTAB_SIZE 1 55 62 #endif 56 63 64 /** The wakeup bit in the INTNETIF::cBusy and INTNETRUNKIF::cBusy counters. */ 65 #define INTNET_BUSY_WAKEUP_MASK RT_BIT_32(30) 57 66 58 67 … … 60 69 * Structures and Typedefs * 61 70 *******************************************************************************/ 62 #ifdef WITH_NEW_STUFF63 71 /** 64 72 * MAC address lookup table entry. … … 80 88 /** Pointer to a MAC address lookup table entry. */ 81 89 typedef INTNETMACTABENTRY *PINTNETMACTABENTRY; 82 /** Pointer to a const MAC address lookup table entry. */83 typedef INTNETMACTABENTRY const *PCINTNETMACTABENTRY;84 90 85 91 /** 86 92 * MAC address lookup table. 93 * 94 * @todo Having this in a separate structure didn't work out as well as it 95 * should. Consider merging it into INTNETNETWORK. 87 96 */ 88 97 typedef struct INTNETMACTAB 89 98 { 90 /** The spinlock protecting the table, interrupt safe. */91 RTSPINLOCK hSpinlock;92 99 /** The current number of entries. */ 93 100 uint32_t cEntries; … … 95 102 uint32_t cEntriesAllocated; 96 103 /** Table entries. */ 97 P CINTNETMACTABENTRYpaEntries;98 99 /** The host MAC address . */104 PINTNETMACTABENTRY paEntries; 105 106 /** The host MAC address (reported). */ 100 107 RTMAC HostMac; 101 /** The host promis cous setting. */108 /** The host promisucous setting (reported). */ 102 109 bool fHostPromiscuous; 103 110 /** Whether the host is active. */ 104 111 bool fHostActive; 105 112 106 /** Whether the wire is promiscuous . */113 /** Whether the wire is promiscuous (config). */ 107 114 bool fWirePromiscuous; 108 115 /** Whether the wire is active. */ … … 127 134 uint32_t cIfs; 128 135 /** The interfaces (referenced). Variable sized array. */ 129 struct INTNETIF *apIfs[1]; 136 struct 137 { 138 /** The destination interface. */ 139 struct INTNETIF *pIf; 140 /** Whether to replace the destination MAC address. 141 * This is used when sharing MAC address with the host on the wire(less). */ 142 bool fReplaceDstMac; 143 } aIfs[1]; 130 144 } INTNETDSTTAB; 131 145 /** Pointer to a destination table. */ 132 146 typedef INTNETDSTTAB *PINTNETDSTTAB; 133 #endif /* WITH_NEW_STUFF */ 147 /** Pointer to a const destination table. */ 148 typedef INTNETDSTTAB const *PCINTNETDSTTAB; 134 149 135 150 … … 199 214 typedef struct INTNETIF 200 215 { 201 /** Pointer to the next interface. 202 * This is protected by the INTNET::FastMutex. */ 203 struct INTNETIF *pNext; 204 /** The current MAC address for the interface. (reported or learned) 205 * Updated while owning the switch table spinlock. */ 206 RTMAC Mac; 207 /** Set if the INTNET::Mac member is valid. */ 216 /** The MAC address. 217 * This is shadowed by INTNETMACTABENTRY::MacAddr. */ 218 RTMAC MacAddr; 219 /** Set if the INTNET::MacAddr member has been explicitly set. */ 208 220 bool fMacSet; 209 221 /** Set if the interface is in promiscuous mode. 210 * In promiscuous mode the interface will receive all packages except the one it's sending. */222 * This is shadowed by INTNETMACTABENTRY::fPromiscuous. */ 211 223 bool fPromiscuous; 212 /** Whether the interface is active or not. */ 224 /** Whether the interface is active or not. 225 * This is shadowed by INTNETMACTABENTRY::fActive. */ 213 226 bool fActive; 214 227 /** Whether someone is currently in the destructor. */ … … 227 240 /** Pointer to ring-3 mapping of the default exchange buffer. */ 228 241 R3PTRTYPE(PINTNETBUF) pIntBufDefaultR3; 229 /** Event semaphore which a receiver thread will sleep on while waiting230 * for data to arrive. */231 RTSEMEVENT volatile Event;232 /** Number of threads sleeping on the Event semaphore. */242 /** Event semaphore which a receiver/consumer thread will sleep on while 243 * waiting for data to arrive. */ 244 RTSEMEVENT volatile hRecvEvent; 245 /** Number of threads sleeping on the event semaphore. */ 233 246 uint32_t cSleepers; 234 247 /** The interface handle. … … 237 250 INTNETIFHANDLE volatile hIf; 238 251 /** Pointer to the network this interface is connected to. 239 * This is protected by the INTNET:: FastMutex. */252 * This is protected by the INTNET::hMtxCreateOpenDestroy. */ 240 253 struct INTNETNETWORK *pNetwork; 241 254 /** The session this interface is associated with. */ … … 243 256 /** The SUPR0 object id. */ 244 257 void *pvObj; 245 /** The network layer address cache. (Indexed by type, 0 entry isn't used.) */ 258 /** The network layer address cache. (Indexed by type, 0 entry isn't used.) 259 * This is protected by the address spinlock of the network. */ 246 260 INTNETADDRCACHE aAddrCache[kIntNetAddrType_End]; 247 #ifdef WITH_NEW_STUFF248 261 /** Spinlock protecting the input (producer) side of the receive ring. */ 249 262 RTSPINLOCK hRecvInSpinlock; 250 263 /** Busy count for tracking destination table references and active sends. 251 * Incremented while owning the switch table spinlock. */ 264 * Usually incremented while owning the switch table spinlock. The 30th bit 265 * is used to indicate wakeup. */ 252 266 uint32_t volatile cBusy; 253 /** Set if a someone is waiting on INTNETNETWORK::hEvtBusyIf for cBusy to254 * reach zero. */255 bool volatile fBusyZeroWakeup;256 267 /** The preallocated destination table. 257 268 * This is NULL when it's in use as a precaution against unserialized 258 269 * transmitting. This is grown when new interfaces are added to the network. */ 259 270 PINTNETDSTTAB volatile pDstTab; 260 #endif /* WITH_NEW_STUFF */261 271 } INTNETIF; 262 272 /** Pointer to an internal network interface. */ … … 273 283 /** The port interface we get from the component. */ 274 284 PINTNETTRUNKIFPORT pIfPort; 275 #ifdef WITH_NEW_STUFF 285 /** The trunk mutex that serializes all calls <b>to</b> the component. */ 276 286 /** @todo This won't quite cut the mustard any longer. That said, GSO 277 287 * segmentation needs to be serialized because of the header buffer. */ 278 RTSEMFASTMUTEX FastMutex; 279 #else 280 /** The trunk mutex that serializes all calls <b>to</b> the component. */ 281 RTSEMFASTMUTEX FastMutex; 282 #endif 288 RTSEMFASTMUTEX FastMutex3; 283 289 /** Pointer to the network we're connect to. 284 290 * This may be NULL if we're orphaned? */ 285 291 struct INTNETNETWORK *pNetwork; 286 #ifdef WITH_NEW_STUFF287 292 /** The current MAC address for the interface. (reported) 288 * Updated while owning the switch table spinlock. 289 * @todo rename to Mac */ 290 RTMAC CachedMac; 291 #else 292 /** The cached MAC address of the interface the trunk is attached to. 293 * This is for the situations where we cannot take the out-bound 294 * semaphore (the recv case) but need to make frame edits (ARP). */ 295 RTMAC CachedMac; 296 #endif 297 #ifndef WITH_NEW_STUFF 298 /** Whether to supply physical addresses with the outbound SGs. (reported) */ 299 bool volatile fPhysSG; 300 /** Set if the 'wire' is in promiscuous mode. 301 * The state of the 'host' is queried each time. */ 302 bool fWirePromiscuous; 303 #else /* WITH_NEW_STUFF */ 304 /** Set if the 'wire' is in promiscuous mode. (config) */ 305 bool fWirePromiscuous; 306 /** Set if the 'host' is in promiscuous mode. (reported) */ 307 bool volatile fHostPromiscuous; 293 * Updated while owning the switch table spinlock. */ 294 RTMAC MacAddr; 308 295 /** Can pfnXmit cope with disabled preemption for the 'wire'. (reported) */ 309 296 bool fWireNoPreempt; … … 312 299 /** Whether to supply physical addresses with the outbound SGs. (reported) */ 313 300 bool fPhysSG; 314 /** Set if a someone is waiting on INTNETNETWORK::hEvtBusyIf for cBusy to315 * reach zero. */316 bool volatile fBusyZeroWakeup;317 301 /** Busy count for tracking destination table references and active sends. 318 * Incremented while owning the switch table spinlock. */ 302 * Usually incremented while owning the switch table spinlock. The 30th bit 303 * is used to indicate wakeup. */ 319 304 uint32_t volatile cBusy; 320 #endif /* WITH_NEW_STUFF */321 305 /** The GSO capabilities of the wire destination. (reported) */ 322 306 uint32_t fWireGsoCapabilites; … … 327 311 /** Header buffer for when we're carving GSO frames. */ 328 312 uint8_t abGsoHdrs[256]; 329 #ifdef WITH_NEW_STUFF 330 /** @todo what exactly to do about the destination tables here? how many do 331 * we need / want? One? One per CPU? */ 332 #endif 313 /** The destination table spinlock, interrupt safe. 314 * Protects apTaskDstTabs and apIntDstTabs. */ 315 RTSPINLOCK hDstTabSpinlock; 316 /** The number of entries in apIntDstTabs. */ 317 uint32_t cIntDstTabs; 318 /** The task time destination tables. 319 * @remarks intnetR0NetworkEnsureTabSpace and others ASSUMES this immediately 320 * preceeds apIntDstTabs so that these two tables can be used as one 321 * contiguous one. */ 322 PINTNETDSTTAB apTaskDstTabs[2]; 323 /** The interrupt / disabled-preemption time destination tables. 324 * This is a variable sized array. */ 325 PINTNETDSTTAB apIntDstTabs[1]; 333 326 } INTNETTRUNKIF; 334 327 /** Pointer to a trunk interface. */ … … 345 338 { 346 339 /** The Next network in the chain. 347 * This is protected by the INTNET:: FastMutex. */340 * This is protected by the INTNET::hMtxCreateOpenDestroy. */ 348 341 struct INTNETNETWORK *pNext; 349 /** List of interfaces connected to the network. 350 * This is protected by the INTNET::FastMutex. */ 351 PINTNETIF pIfs; 352 /** Pointer to the trunk interface. 353 * Can be NULL if there is no trunk connection. */ 354 PINTNETTRUNKIF pTrunkIF; 355 /** The network mutex. 356 * It protects everything dealing with this network. */ 357 #ifdef WITH_NEW_STUFF 358 /** @todo Make this a mutex so we can block on the event semaphore while holding 359 * it. Requires fixing the mutex code on linux... Or maybe add 360 * another mutex for creation / destruction serilization. */ 361 #endif 362 RTSEMFASTMUTEX FastMutex2; 363 #ifdef WITH_NEW_STUFF 342 343 /** The spinlock protecting MacTab and INTNETTRUNKIF::aAddrCache. 344 * Interrupt safe. */ 345 RTSPINLOCK hAddrSpinlock; 346 /** MAC address table. 347 * This doubles as interface collection. */ 348 INTNETMACTAB MacTab; 349 364 350 /** Wait for an interface to stop being busy so it can be removed or have its 365 351 * destination table replaced. We have to wait upon this while owning the 366 * network mutex. */352 * network mutex. Will only ever have one waiter because of the big mutex. */ 367 353 RTSEMEVENT hEvtBusyIf; 368 #endif369 354 /** Pointer to the instance data. */ 370 355 struct INTNET *pIntNet; … … 606 591 607 592 608 #ifdef WITH_NEW_STUFF 609 610 /** 611 * Compares two MAC addresses. 612 * 613 * @returns true if equal, false if not. 614 * @param pDstAddr1 Address 1. 615 * @param pDstAddr2 Address 2. 616 */ 617 DECL_FORCE_INLINE(bool) intnetR0AreMacAddrsEqual(PCRTMAC pDstAddr1, PCRTMAC pDstAddr2) 618 { 619 return pDstAddr1->au16[2] == pDstAddr2->au16[2] 620 && pDstAddr1->au16[1] == pDstAddr2->au16[1] 621 && pDstAddr1->au16[0] == pDstAddr2->au16[0]; 622 } 623 624 625 /** 626 * Switch a MAC address and return a destination table. 627 * 628 * @returns Destination table or NULL if *ppDstTab is NULL. 629 * @param pTab The MAC address table to work on. 630 * @param pDstAddr The destination address of the packet. 631 * @param ppDstTab Where to get the destination table from. 632 * @param pcBusy The busy counter to increment if *ppDstTab isn't 633 * NULL. 634 */ 635 static PINTNETDSTTAB intnetR0MacTabSwitch(PINTNETMACTAB pTab, PCRTMAC pDstAddr, 636 PINTNETDSTTAB volatile *ppDstTab, uint32_t volatile *pcBusy) 637 { 638 /* 639 * Grab the spinlock first, then get the destination table and increment 640 * the busy counter (to indicate that we're using the dst tab and it cannot 641 * be freed yet). 642 */ 643 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 644 RTSpinlockAcquire(pTab->hSpinlock, &Tmp); 645 PINTNETDSTTAB pDstTab = (PINTNETDSTTAB)ASMAtomicXchgPtr((void * volatile *)ppDstTab, NULL); 646 if (pDstTab) 647 { 648 ASMAtomicIncU32(pcBusy); 649 650 /* 651 * Do the switching. 652 */ 653 pDstTab->fTrunkDst = 0; 654 pDstTab->pTrunk = 0; 655 pDstTab->cIfs = 0; 656 657 uint32_t i = pTab->cEntries; 658 if (pDstAddr->au8[0] & 1) /* multicast or broadcast address */ 659 { 660 /* Broadcast/multicast - add all active interfaces. */ 661 while (i-- > 0) 662 { 663 if (pTab->paEntries[i].fActive) 664 { 665 PINTNETIF pIf = pTab->paEntries[i].pIf; 666 pDstTab->apIfs[i] = pIf; 667 ASMAtomicIncU32(&pIf->cBusy); 668 pDstTab->cIfs++; 669 } 670 } 671 672 if (pTab->fHostActive) 673 pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST; 674 if (pTab->fWireActive) 675 pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE; 676 } 677 else 678 { 679 /* Find exactly matching or promiscuous interfaces. */ 680 uint32_t cExactHits = 0; 681 while (i-- > 0) 682 { 683 if (pTab->paEntries[i].fActive) 684 { 685 bool fExact = intnetR0AreMacAddrsEqual(&pTab->paEntries[i].MacAddr, pDstAddr); 686 if (fExact || pTab->paEntries[i].fPromiscuous) 687 { 688 cExactHits += fExact; 689 690 PINTNETIF pIf = pTab->paEntries[i].pIf; 691 pDstTab->apIfs[i] = pIf; 692 ASMAtomicIncU32(&pIf->cBusy); 693 pDstTab->cIfs++; 694 } 695 } 696 } 697 698 /* Does it match the host, or is the host promiscuous? */ 699 if (pTab->fHostActive) 700 { 701 bool fExact = intnetR0AreMacAddrsEqual(&pTab->HostMac, pDstAddr); 702 if (pTab->fHostPromiscuous) 703 { 704 cExactHits += fExact; 705 pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST; 706 } 707 } 708 709 /* Hit the wire if there are no exact matches or if it's in promiscuous mode. */ 710 if (pTab->fWireActive && (!cExactHits || pTab->fWirePromiscuous)) 711 pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE; 712 } 713 714 /* Grab the trunk if we're sending to it. */ 715 if (pDstTab->fTrunkDst) 716 { 717 PINTNETTRUNKIF pTrunkIf = pTab->pTrunk; 718 pDstTab->pTrunk = pTrunkIf; 719 ASMAtomicIncU32(&pTrunkIf->cBusy); 720 } 721 } 722 723 RTSpinlockRelease(pTab->hSpinlock, &Tmp); 724 return pDstTab; 725 } 726 727 728 #endif /* WITH_NEW_STUFF */ 593 /** 594 * Wait for a busy counter to reach zero. 595 * 596 * @param pNetwork The network. 597 * @param pcBusy The busy counter. 598 */ 599 static void intnetR0BusyWait(PINTNETNETWORK pNetwork, uint32_t volatile *pcBusy) 600 { 601 if (ASMAtomicReadU32(pcBusy) == 0) 602 return; 603 604 /* 605 * We have to be a bit cautious here so we don't destroy the network or the 606 * semaphore before intnetR0BusyDec has signalled us. 607 */ 608 609 /* Reset the semaphore and flip the wakeup bit. */ 610 RTSemEventWait(pNetwork->hEvtBusyIf, 0); /* clear it */ 611 uint32_t cCurBusy = ASMAtomicReadU32(pcBusy); 612 do 613 { 614 if (cCurBusy == 0) 615 return; 616 AssertMsg(!(cCurBusy & INTNET_BUSY_WAKEUP_MASK), ("%#x\n", cCurBusy)); 617 AssertMsg((cCurBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cCurBusy)); 618 } while (!ASMAtomicCmpXchgExU32(pcBusy, cCurBusy | INTNET_BUSY_WAKEUP_MASK, cCurBusy, &cCurBusy)); 619 620 /* Wait for the count to reach zero. */ 621 do 622 { 623 int rc2 = RTSemEventWait(pNetwork->hEvtBusyIf, 30000); NOREF(rc2); 624 //AssertMsg(RT_SUCCESS(rc2), ("rc=%Rrc *pcBusy=%#x (%#x)\n", rc2, ASMAtomicReadU32(pcBusy), cCurBusy )); 625 cCurBusy = ASMAtomicReadU32(pcBusy); 626 AssertMsg((cCurBusy & INTNET_BUSY_WAKEUP_MASK), ("%#x\n", cCurBusy)); 627 AssertMsg((cCurBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cCurBusy)); 628 } while ( cCurBusy != INTNET_BUSY_WAKEUP_MASK 629 || ASMAtomicCmpXchgU32(pcBusy, 0, INTNET_BUSY_WAKEUP_MASK)); 630 } 631 632 633 /** 634 * Decrements the busy counter and maybe wakes up any threads waiting for it to 635 * reach zero. 636 * 637 * @param pNetwork The network. 638 * @param pcBusy The busy counter. 639 */ 640 DECLINLINE(void) intnetR0BusyDec(PINTNETNETWORK pNetwork, uint32_t volatile *pcBusy) 641 { 642 uint32_t cNewBusy = ASMAtomicDecU32(pcBusy); 643 if (RT_UNLIKELY( cNewBusy == INTNET_BUSY_WAKEUP_MASK 644 && pNetwork)) 645 RTSemEventSignal(pNetwork->hEvtBusyIf); 646 AssertMsg((cNewBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cNewBusy)); 647 } 648 649 650 /** 651 * Increments the busy count of the specified interface. 652 * 653 * The caller must own the MAC address table spinlock. 654 * 655 * @param pIf The interface. 656 */ 657 DECLINLINE(void) intnetR0BusyDecIf(PINTNETIF pIf) 658 { 659 intnetR0BusyDec(pIf->pNetwork, &pIf->cBusy); 660 } 661 662 663 /** 664 * Increments the busy count of the specified interface. 665 * 666 * The caller must own the MAC address table spinlock or an explicity reference. 667 * 668 * @param pTrunk The trunk. 669 */ 670 DECLINLINE(void) intnetR0BusyDecTrunk(PINTNETTRUNKIF pTrunk) 671 { 672 intnetR0BusyDec(pTrunk->pNetwork, &pTrunk->cBusy); 673 } 674 675 676 /** 677 * Increments the busy count of the specified interface. 678 * 679 * The caller must own the MAC address table spinlock or an explicity reference. 680 * 681 * @param pIf The interface. 682 */ 683 DECLINLINE(void) intnetR0BusyIncIf(PINTNETIF pIf) 684 { 685 uint32_t cNewBusy = ASMAtomicIncU32(&pIf->cBusy); 686 AssertMsg((cNewBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cNewBusy)); 687 NOREF(cNewBusy); 688 } 689 690 691 /** 692 * Increments the busy count of the specified interface. 693 * 694 * The caller must own the MAC address table spinlock or an explicity reference. 695 * 696 * @param pTrunk The trunk. 697 */ 698 DECLINLINE(void) intnetR0BusyIncTrunk(PINTNETTRUNKIF pTrunk) 699 { 700 uint32_t cNewBusy = ASMAtomicIncU32(&pTrunk->cBusy); 701 AssertMsg((cNewBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cNewBusy)); 702 NOREF(cNewBusy); 703 } 729 704 730 705 … … 784 759 785 760 786 761 /** 762 * Checks if the interface has a usable MAC address or not. 763 * 764 * @returns true if MacAddr is usable, false if not. 765 * @param pIf The interface. 766 */ 767 DECL_FORCE_INLINE(bool) intnetR0IfHasMacAddr(PINTNETIF pIf) 768 { 769 return pIf->fMacSet || !(pIf->MacAddr.au8[0] & 1); 770 } 771 772 773 /** 774 * Locates the MAC address table entry for the given interface. 775 * 776 * The caller holds the MAC address table spinlock, obviously. 777 * 778 * @returns Pointer to the entry on if found, NULL if not. 779 * @param pNetwork The network. 780 * @param pIf The interface. 781 */ 782 DECLINLINE(PINTNETMACTABENTRY) intnetR0NetworkFindMacAddrEntry(PINTNETNETWORK pNetwork, PINTNETIF pIf) 783 { 784 uint32_t iIf = pNetwork->MacTab.cEntries; 785 while (iIf-- > 0) 786 { 787 if (pNetwork->MacTab.paEntries[iIf].pIf == pIf) 788 return &pNetwork->MacTab.paEntries[iIf]; 789 } 790 return NULL; 791 } 787 792 788 793 … … 1021 1026 case kIntNetAddrType_IPv4: 1022 1027 Log(("intnetR0IfAddrCacheDeleteIt: hIf=%#x MAC=%.6Rhxs IPv4 added #%d %d.%d.%d.%d %s\n", 1023 pIf->hIf, &pIf->Mac , iEntry, pAddr->au8[0], pAddr->au8[1], pAddr->au8[2], pAddr->au8[3], pszMsg));1028 pIf->hIf, &pIf->MacAddr, iEntry, pAddr->au8[0], pAddr->au8[1], pAddr->au8[2], pAddr->au8[3], pszMsg)); 1024 1029 break; 1025 1030 default: 1026 1031 Log(("intnetR0IfAddrCacheDeleteIt: hIf=%RX32 MAC=%.6Rhxs type=%d #%d %.*Rhxs %s\n", 1027 pIf->hIf, &pIf->Mac , enmAddrType, iEntry, pCache->cbAddress, pAddr, pszMsg));1032 pIf->hIf, &pIf->MacAddr, enmAddrType, iEntry, pCache->cbAddress, pAddr, pszMsg)); 1028 1033 break; 1029 1034 } … … 1041 1046 * Deletes an address from the cache, assuming it isn't actually in the cache. 1042 1047 * 1048 * May or may not own the spinlock when calling this. 1049 * 1043 1050 * @param pIf The interface (for logging). 1044 1051 * @param pCache The cache. … … 1069 1076 uint8_t const cbAddr, const char *pszMsg) 1070 1077 { 1071 for (PINTNETIF pIf = pNetwork->pIfs; pIf; pIf = pIf->pNext) 1072 { 1078 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 1079 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 1080 1081 uint32_t iIf = pNetwork->MacTab.cEntries; 1082 while (iIf--) 1083 { 1084 PINTNETIF pIf = pNetwork->MacTab.paEntries[iIf].pIf; 1073 1085 int i = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmType], pAddr, cbAddr); 1074 1086 if (RT_UNLIKELY(i >= 0)) 1075 1087 intnetR0IfAddrCacheDeleteIt(pIf, &pIf->aAddrCache[enmType], i, pszMsg); 1076 1088 } 1089 1090 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 1077 1091 } 1078 1092 … … 1093 1107 INTNETADDRTYPE const enmType, uint8_t const cbAddr, const char *pszMsg) 1094 1108 { 1095 for (PINTNETIF pIf = pNetwork->pIfs; pIf; pIf = pIf->pNext) 1109 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 1110 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 1111 1112 uint32_t iIf = pNetwork->MacTab.cEntries; 1113 while (iIf--) 1114 { 1115 PINTNETIF pIf = pNetwork->MacTab.paEntries[iIf].pIf; 1096 1116 if (pIf != pIfSender) 1097 1117 { … … 1100 1120 intnetR0IfAddrCacheDeleteIt(pIf, &pIf->aAddrCache[enmType], i, pszMsg); 1101 1121 } 1122 } 1123 1124 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 1102 1125 } 1103 1126 … … 1107 1130 * having it in its address cache. 1108 1131 * 1109 * @returns Pointer to the interface on success, NULL if not found. 1132 * @returns Pointer to the interface on success, NULL if not found. The caller 1133 * must release the interface by calling intnetR0BusyDecIf. 1110 1134 * @param pNetwork The network. 1111 1135 * @param pAddr The address to lookup. … … 1115 1139 DECLINLINE(PINTNETIF) intnetR0NetworkAddrCacheLookupIf(PINTNETNETWORK pNetwork, PCRTNETADDRU pAddr, INTNETADDRTYPE const enmType, uint8_t const cbAddr) 1116 1140 { 1117 for (PINTNETIF pIf = pNetwork->pIfs; pIf; pIf = pIf->pNext) 1118 { 1141 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 1142 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 1143 1144 uint32_t iIf = pNetwork->MacTab.cEntries; 1145 while (iIf--) 1146 { 1147 PINTNETIF pIf = pNetwork->MacTab.paEntries[iIf].pIf; 1119 1148 int i = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmType], pAddr, cbAddr); 1120 1149 if (i >= 0) 1150 { 1151 intnetR0BusyIncIf(pIf); 1152 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 1121 1153 return pIf; 1122 } 1154 } 1155 } 1156 1157 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 1123 1158 return NULL; 1124 1159 } … … 1126 1161 1127 1162 /** 1128 * Adds an address to the cache, the caller is responsible for making sure it' 1129 * s not already in the cache. 1163 * Adds an address to the cache, the caller is responsible for making sure it's 1164 * not already in the cache. 1165 * 1166 * The caller must not 1130 1167 * 1131 1168 * @param pIf The interface (for logging). … … 1136 1173 static void intnetR0IfAddrCacheAddIt(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, const char *pszMsg) 1137 1174 { 1175 PINTNETNETWORK pNetwork = pIf->pNetwork; 1176 AssertReturnVoid(pNetwork); 1177 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 1178 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 1179 1138 1180 if (!pCache->cEntriesAlloc) 1139 1181 { 1140 /* Allocate the first array */ 1141 pCache->pbEntries = (uint8_t *)RTMemAllocZ(pCache->cbEntry * 16); 1142 if (!pCache->pbEntries) 1182 /* Allocate the table - 64 entries. */ 1183 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 1184 uint8_t *pbEntries = (uint8_t *)RTMemAllocZ(pCache->cbEntry * 64); 1185 if (!pbEntries) 1143 1186 return; 1144 pCache->cEntriesAlloc = 16; 1145 } 1146 else if (pCache->cEntries >= pCache->cEntriesAlloc) 1147 { 1148 bool fReplace = true; 1149 if (pCache->cEntriesAlloc < 64) 1187 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 1188 if (!pCache->cEntriesAlloc) 1150 1189 { 1151 uint8_t cEntriesAlloc = pCache->cEntriesAlloc + 16; 1152 void *pvNew = RTMemRealloc(pCache->pbEntries, pCache->cbEntry * cEntriesAlloc); 1153 if (pvNew) 1154 { 1155 pCache->pbEntries = (uint8_t *)pvNew; 1156 pCache->cEntriesAlloc = cEntriesAlloc; 1157 fReplace = false; 1158 } 1190 pCache->pbEntries = pbEntries; 1191 pCache->cEntriesAlloc = 64; 1159 1192 } 1160 if (fReplace)1193 else 1161 1194 { 1162 /* simple FIFO, might consider usage/ageing here... */ 1163 Log(("intnetR0IfAddrCacheAddIt: type=%d replacing %.*Rhxs\n", 1164 (int)(uintptr_t)(pCache - &pIf->aAddrCache[0]), pCache->cbAddress, pCache->pbEntries)); 1165 memmove(pCache->pbEntries, pCache->pbEntries + pCache->cbEntry, pCache->cbEntry * (pCache->cEntries - 1)); 1166 pCache->cEntries--; 1195 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 1196 RTMemFree(pbEntries); 1197 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 1167 1198 } 1199 } 1200 else 1201 { 1202 /* simple FIFO, might consider usage/ageing here... */ 1203 Log(("intnetR0IfAddrCacheAddIt: type=%d replacing %.*Rhxs\n", 1204 (int)(uintptr_t)(pCache - &pIf->aAddrCache[0]), pCache->cbAddress, pCache->pbEntries)); 1205 memmove(pCache->pbEntries, pCache->pbEntries + pCache->cbEntry, pCache->cbEntry * (pCache->cEntries - 1)); 1206 pCache->cEntries--; 1168 1207 } 1169 1208 … … 1180 1219 case kIntNetAddrType_IPv4: 1181 1220 Log(("intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs IPv4 added #%d %d.%d.%d.%d %s\n", 1182 pIf->hIf, &pIf->Mac , pCache->cEntries, pAddr->au8[0], pAddr->au8[1], pAddr->au8[2], pAddr->au8[3], pszMsg));1221 pIf->hIf, &pIf->MacAddr, pCache->cEntries, pAddr->au8[0], pAddr->au8[1], pAddr->au8[2], pAddr->au8[3], pszMsg)); 1183 1222 break; 1184 1223 default: 1185 1224 Log(("intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs type=%d added #%d %.*Rhxs %s\n", 1186 pIf->hIf, &pIf->Mac , enmAddrType, pCache->cEntries, pCache->cbAddress, pAddr, pszMsg));1225 pIf->hIf, &pIf->MacAddr, enmAddrType, pCache->cEntries, pCache->cbAddress, pAddr, pszMsg)); 1187 1226 break; 1188 1227 } … … 1190 1229 pCache->cEntries++; 1191 1230 Assert(pCache->cEntries <= pCache->cEntriesAlloc); 1231 1232 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 1192 1233 } 1193 1234 … … 1228 1269 * Adds an address to the cache if it's not already there. 1229 1270 * 1271 * Must not own any spinlocks when calling this function. 1272 * 1230 1273 * @param pIf The interface (for logging). 1231 1274 * @param pCache The address cache. … … 1234 1277 * @param pszMsg Log message. 1235 1278 */ 1236 DECLINLINE(void) intnetR0IfAddrCacheAdd(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr, const char *pszMsg) 1279 DECLINLINE(void) intnetR0IfAddrCacheAdd(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, 1280 uint8_t const cbAddr, const char *pszMsg) 1237 1281 { 1238 1282 Assert(pCache->cbAddress == cbAddr); … … 1249 1293 intnetR0IfAddrCacheAddSlow(pIf, pCache, pAddr, cbAddr, pszMsg); 1250 1294 } 1295 1296 1297 /** 1298 * Is it a multicast or broadcast MAC address? 1299 * 1300 * @returns true if multicast, false if not. 1301 * @param pMacAddr The address to inspect. 1302 */ 1303 DECL_FORCE_INLINE(bool) intnetR0IsMacAddrMulticast(PCRTMAC pMacAddr) 1304 { 1305 return !!(pMacAddr->au8[0] & 0x01); 1306 } 1307 1308 1309 /** 1310 * Is it a dummy MAC address? 1311 * 1312 * We use dummy MAC addresses for interfaces which we don't know the MAC 1313 * address of because they haven't sent anything (learning) or explicitly set 1314 * it. 1315 * 1316 * @returns true if dummy, false if not. 1317 * @param pMacAddr The address to inspect. 1318 */ 1319 DECL_FORCE_INLINE(bool) intnetR0IsMacAddrDummy(PCRTMAC pMacAddr) 1320 { 1321 /* The dummy address are broadcast addresses, don't bother check it all. */ 1322 return pMacAddr->au16[0] == 0xffff; 1323 } 1324 1325 1326 /** 1327 * Compares two MAC addresses. 1328 * 1329 * @returns true if equal, false if not. 1330 * @param pDstAddr1 Address 1. 1331 * @param pDstAddr2 Address 2. 1332 */ 1333 DECL_FORCE_INLINE(bool) intnetR0AreMacAddrsEqual(PCRTMAC pDstAddr1, PCRTMAC pDstAddr2) 1334 { 1335 return pDstAddr1->au16[2] == pDstAddr2->au16[2] 1336 && pDstAddr1->au16[1] == pDstAddr2->au16[1] 1337 && pDstAddr1->au16[0] == pDstAddr2->au16[0]; 1338 } 1339 1340 1341 /** 1342 * Switch a unicast frame based on the network layer address (OSI level 3) and 1343 * return a destination table. 1344 * 1345 * @returns INTNETSWDECISION_DROP, INTNETSWDECISION_TRUNK, 1346 * INTNETSWDECISION_INTNET or INTNETSWDECISION_BROADCAST (misnomer). 1347 * @param pNetwork The network to switch on. 1348 * @param pDstMacAddr The destination MAC address. 1349 * @param enmL3AddrType The level-3 destination address type. 1350 * @param pL3Addr The level-3 destination address. 1351 * @param cbL3Addr The size of the level-3 destination address. 1352 * @param fSrc The frame source (INTNETTRUNKDIR_WIRE). 1353 * @param pDstTab The destination output table. 1354 */ 1355 static INTNETSWDECISION intnetR0NetworkSwitchLevel3(PINTNETNETWORK pNetwork, PCRTMAC pDstMacAddr, 1356 INTNETADDRTYPE enmL3AddrType, PCRTNETADDRU pL3Addr, uint8_t cbL3Addr, 1357 uint32_t fSrc, PINTNETDSTTAB pDstTab) 1358 { 1359 Assert(fSrc == INTNETTRUNKDIR_WIRE); 1360 1361 /* 1362 * Grab the spinlock first and do the switching. 1363 */ 1364 PINTNETMACTAB pTab = &pNetwork->MacTab; 1365 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 1366 RTSpinlockAcquire(pNetwork->hAddrSpinlock, &Tmp); 1367 1368 pDstTab->fTrunkDst = 0; 1369 pDstTab->pTrunk = 0; 1370 pDstTab->cIfs = 0; 1371 1372 /* Find exactly matching or promiscuous interfaces. */ 1373 uint32_t cExactHits = 0; 1374 uint32_t iIfMac = pTab->cEntries; 1375 while (iIfMac-- > 0) 1376 { 1377 if (pTab->paEntries[iIfMac].fActive) 1378 { 1379 PINTNETIF pIf = pTab->paEntries[iIfMac].pIf; AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork); 1380 bool fExact = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmL3AddrType], pL3Addr, cbL3Addr); 1381 if (fExact || pTab->paEntries[iIfMac].fPromiscuous) 1382 { 1383 cExactHits += fExact; 1384 1385 uint32_t iIfDst = pDstTab->cIfs++; 1386 pDstTab->aIfs[iIfDst].pIf = pIf; 1387 pDstTab->aIfs[iIfDst].fReplaceDstMac = fExact; 1388 intnetR0BusyIncIf(pIf); 1389 } 1390 } 1391 } 1392 1393 /* Does it match the host, or is the host promiscuous? */ 1394 if (pTab->fHostActive) 1395 { 1396 bool fExact = intnetR0AreMacAddrsEqual(&pTab->HostMac, pDstMacAddr); 1397 if ( fExact 1398 || intnetR0IsMacAddrDummy(&pTab->HostMac) 1399 || pTab->fHostPromiscuous) 1400 { 1401 cExactHits += fExact; 1402 pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST; 1403 } 1404 } 1405 1406 /* Hit the wire if there are no exact matches or if it's in promiscuous mode. */ 1407 if (pTab->fWireActive && (!cExactHits || pTab->fWirePromiscuous)) 1408 pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE; 1409 pDstTab->fTrunkDst &= ~fSrc; 1410 if (pDstTab->fTrunkDst) 1411 { 1412 PINTNETTRUNKIF pTrunk = pTab->pTrunk; 1413 pDstTab->pTrunk = pTrunk; 1414 intnetR0BusyIncTrunk(pTrunk); 1415 } 1416 1417 RTSpinlockRelease(pNetwork->hAddrSpinlock, &Tmp); 1418 return pDstTab->cIfs 1419 ? (!pDstTab->fTrunkDst ? INTNETSWDECISION_INTNET : INTNETSWDECISION_BROADCAST) 1420 : (!pDstTab->fTrunkDst ? INTNETSWDECISION_DROP : INTNETSWDECISION_TRUNK); 1421 } 1422 1423 1424 /** 1425 * Switch a unicast MAC address and return a destination table. 1426 * 1427 * @returns INTNETSWDECISION_DROP, INTNETSWDECISION_TRUNK, 1428 * INTNETSWDECISION_INTNET or INTNETSWDECISION_BROADCAST (misnomer). 1429 * @param pNetwork The network to switch on. 1430 * @param fSrc The frame source. 1431 * @param pIfSender The sender interface, NULL if trunk. Used to 1432 * prevent sending an echo to the sender. 1433 * @param pDstAddr The destination address of the frame. 1434 * @param pDstTab The destination output table. 1435 */ 1436 static INTNETSWDECISION intnetR0NetworkSwitchUnicast(PINTNETNETWORK pNetwork, uint32_t fSrc, PINTNETIF pIfSender, 1437 PCRTMAC pDstAddr, PINTNETDSTTAB pDstTab) 1438 { 1439 AssertPtr(pDstTab); 1440 Assert(!intnetR0IsMacAddrMulticast(pDstAddr)); 1441 1442 /* 1443 * Grab the spinlock first and do the switching. 1444 */ 1445 PINTNETMACTAB pTab = &pNetwork->MacTab; 1446 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 1447 RTSpinlockAcquire(pNetwork->hAddrSpinlock, &Tmp); 1448 1449 pDstTab->fTrunkDst = 0; 1450 pDstTab->pTrunk = 0; 1451 pDstTab->cIfs = 0; 1452 1453 /* Find exactly matching or promiscuous interfaces. */ 1454 uint32_t cExactHits = 0; 1455 uint32_t iIfMac = pTab->cEntries; 1456 while (iIfMac-- > 0) 1457 { 1458 if (pTab->paEntries[iIfMac].fActive) 1459 { 1460 bool fExact = intnetR0AreMacAddrsEqual(&pTab->paEntries[iIfMac].MacAddr, pDstAddr); 1461 if ( fExact 1462 || intnetR0IsMacAddrDummy(&pTab->paEntries[iIfMac].MacAddr) 1463 || pTab->paEntries[iIfMac].fPromiscuous) 1464 { 1465 cExactHits += fExact; 1466 1467 PINTNETIF pIf = pTab->paEntries[iIfMac].pIf; AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork); 1468 if (RT_LIKELY(pIf != pIfSender)) /* paranoia */ 1469 { 1470 uint32_t iIfDst = pDstTab->cIfs++; 1471 pDstTab->aIfs[iIfDst].pIf = pIf; 1472 pDstTab->aIfs[iIfDst].fReplaceDstMac = false; 1473 intnetR0BusyIncIf(pIf); 1474 } 1475 } 1476 } 1477 } 1478 1479 /* Does it match the host, or is the host promiscuous? */ 1480 if ( fSrc != INTNETTRUNKDIR_HOST 1481 && pTab->fHostActive) 1482 { 1483 bool fExact = intnetR0AreMacAddrsEqual(&pTab->HostMac, pDstAddr); 1484 if ( fExact 1485 || intnetR0IsMacAddrDummy(&pTab->HostMac) 1486 || pTab->fHostPromiscuous) 1487 { 1488 cExactHits += fExact; 1489 pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST; 1490 } 1491 } 1492 1493 /* Hit the wire if there are no exact matches or if it's in promiscuous mode. */ 1494 if ( fSrc != INTNETTRUNKDIR_WIRE 1495 && pTab->fWireActive 1496 && (!cExactHits || pTab->fWirePromiscuous) 1497 ) 1498 pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE; 1499 1500 /* Grab the trunk if we're sending to it. */ 1501 if (pDstTab->fTrunkDst) 1502 { 1503 PINTNETTRUNKIF pTrunk = pTab->pTrunk; 1504 pDstTab->pTrunk = pTrunk; 1505 intnetR0BusyIncTrunk(pTrunk); 1506 } 1507 1508 RTSpinlockRelease(pNetwork->hAddrSpinlock, &Tmp); 1509 return pDstTab->cIfs 1510 ? (!pDstTab->fTrunkDst ? INTNETSWDECISION_INTNET : INTNETSWDECISION_BROADCAST) 1511 : (!pDstTab->fTrunkDst ? INTNETSWDECISION_DROP : INTNETSWDECISION_TRUNK); 1512 } 1513 1514 1515 /** 1516 * Create a destination table for a broadcast frame. 1517 * 1518 * @returns INTNETSWDECISION_BROADCAST. 1519 * @param pNetwork The network to switch on. 1520 * @param fSrc The frame source. 1521 * @param pIfSender The sender interface, NULL if trunk. Used to 1522 * prevent sending an echo to the sender. 1523 * @param pDstTab The destination output table. 1524 */ 1525 static INTNETSWDECISION intnetR0NetworkSwitchBroadcast(PINTNETNETWORK pNetwork, uint32_t fSrc, PINTNETIF pIfSender, 1526 PINTNETDSTTAB pDstTab) 1527 { 1528 AssertPtr(pDstTab); 1529 1530 /* 1531 * Grab the spinlock first and record all active interfaces. 1532 */ 1533 PINTNETMACTAB pTab = &pNetwork->MacTab; 1534 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 1535 RTSpinlockAcquire(pNetwork->hAddrSpinlock, &Tmp); 1536 1537 pDstTab->fTrunkDst = 0; 1538 pDstTab->pTrunk = 0; 1539 pDstTab->cIfs = 0; 1540 1541 /* Regular interfaces. */ 1542 uint32_t iIfMac = pTab->cEntries; 1543 while (iIfMac-- > 0) 1544 { 1545 if (pTab->paEntries[iIfMac].fActive) 1546 { 1547 PINTNETIF pIf = pTab->paEntries[iIfMac].pIf; AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork); 1548 if (pIf != pIfSender) 1549 { 1550 uint32_t iIfDst = pDstTab->cIfs++; 1551 pDstTab->aIfs[iIfDst].pIf = pIf; 1552 pDstTab->aIfs[iIfDst].fReplaceDstMac = false; 1553 intnetR0BusyIncIf(pIf); 1554 } 1555 } 1556 } 1557 1558 /* The trunk interface. */ 1559 if (pTab->fHostActive) 1560 pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST; 1561 if (pTab->fWireActive) 1562 pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE; 1563 pDstTab->fTrunkDst &= ~fSrc; 1564 if (pDstTab->fTrunkDst) 1565 { 1566 PINTNETTRUNKIF pTrunk = pTab->pTrunk; 1567 pDstTab->pTrunk = pTrunk; 1568 intnetR0BusyIncTrunk(pTrunk); 1569 } 1570 1571 RTSpinlockRelease(pNetwork->hAddrSpinlock, &Tmp); 1572 return INTNETSWDECISION_BROADCAST; 1573 } 1574 1575 1576 /** 1577 * Create a destination table with the trunk and any promiscuous interfaces. 1578 * 1579 * This is only used in a fallback case of the level-3 switching, so we can 1580 * assume the wire as source and skip the sender interface filtering. 1581 * 1582 * @returns INTNETSWDECISION_DROP, INTNETSWDECISION_TRUNK, 1583 * INTNETSWDECISION_INTNET or INTNETSWDECISION_BROADCAST (misnomer). 1584 * @param pNetwork The network to switch on. 1585 * @param fSrc The frame source. 1586 * @param pDstTab The destination output table. 1587 */ 1588 static INTNETSWDECISION intnetR0NetworkSwitchTrunkAndPromisc(PINTNETNETWORK pNetwork, uint32_t fSrc, PINTNETDSTTAB pDstTab) 1589 { 1590 Assert(fSrc == INTNETTRUNKDIR_WIRE); 1591 1592 /* 1593 * Grab the spinlock first and do the switching. 1594 */ 1595 PINTNETMACTAB pTab = &pNetwork->MacTab; 1596 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 1597 RTSpinlockAcquire(pNetwork->hAddrSpinlock, &Tmp); 1598 1599 pDstTab->fTrunkDst = 0; 1600 pDstTab->pTrunk = 0; 1601 pDstTab->cIfs = 0; 1602 1603 /* Find promiscuous interfaces. */ 1604 uint32_t iIfMac = pTab->cEntries; 1605 while (iIfMac-- > 0) 1606 { 1607 if ( pTab->paEntries[iIfMac].fActive 1608 && pTab->paEntries[iIfMac].fPromiscuous) 1609 { 1610 PINTNETIF pIf = pTab->paEntries[iIfMac].pIf; AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork); 1611 uint32_t iIfDst = pDstTab->cIfs++; 1612 pDstTab->aIfs[iIfDst].pIf = pIf; 1613 pDstTab->aIfs[iIfDst].fReplaceDstMac = false; 1614 intnetR0BusyIncIf(pIf); 1615 } 1616 } 1617 1618 /* The trunk interface. */ 1619 if (pTab->fHostActive) 1620 pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST; 1621 if (pTab->fWireActive) 1622 pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE; 1623 pDstTab->fTrunkDst &= ~fSrc; 1624 if (pDstTab->fTrunkDst) 1625 { 1626 PINTNETTRUNKIF pTrunk = pTab->pTrunk; 1627 pDstTab->pTrunk = pTrunk; 1628 intnetR0BusyIncTrunk(pTrunk); 1629 } 1630 1631 RTSpinlockRelease(pNetwork->hAddrSpinlock, &Tmp); 1632 return !pDstTab->cIfs 1633 ? (!pDstTab->fTrunkDst ? INTNETSWDECISION_DROP : INTNETSWDECISION_TRUNK) 1634 : (!pDstTab->fTrunkDst ? INTNETSWDECISION_INTNET : INTNETSWDECISION_BROADCAST); 1635 } 1636 1637 1638 /** 1639 * Create a destination table for a trunk frame. 1640 * 1641 * @returns INTNETSWDECISION_BROADCAST. 1642 * @param pNetwork The network to switch on. 1643 * @param fSrc The frame source. 1644 * @param pDstTab The destination output table. 1645 */ 1646 static INTNETSWDECISION intnetR0NetworkSwitchTrunk(PINTNETNETWORK pNetwork, uint32_t fSrc, PINTNETDSTTAB pDstTab) 1647 { 1648 AssertPtr(pDstTab); 1649 1650 /* 1651 * Grab the spinlock first and record all active interfaces. 1652 */ 1653 PINTNETMACTAB pTab= &pNetwork->MacTab; 1654 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 1655 RTSpinlockAcquire(pNetwork->hAddrSpinlock, &Tmp); 1656 1657 pDstTab->fTrunkDst = 0; 1658 pDstTab->pTrunk = 0; 1659 pDstTab->cIfs = 0; 1660 1661 /* The trunk interface. */ 1662 if (pTab->fHostActive) 1663 pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST; 1664 if (pTab->fWireActive) 1665 pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE; 1666 pDstTab->fTrunkDst &= ~fSrc; 1667 if (pDstTab->fTrunkDst) 1668 { 1669 PINTNETTRUNKIF pTrunk = pTab->pTrunk; 1670 pDstTab->pTrunk = pTrunk; 1671 intnetR0BusyIncTrunk(pTrunk); 1672 } 1673 1674 RTSpinlockRelease(pNetwork->hAddrSpinlock, &Tmp); 1675 return pDstTab->fTrunkDst ? INTNETSWDECISION_TRUNK : INTNETSWDECISION_DROP; 1676 } 1677 1678 1679 /** 1680 * Wrapper around RTMemAlloc for allocating a destination table. 1681 * 1682 * @returns VINF_SUCCESS or VERR_NO_MEMORY. 1683 * @param cEntries The size given as an entry count. 1684 * @param ppDstTab Where to store the pointer (always). 1685 */ 1686 DECLINLINE(int) intnetR0AllocDstTab(uint32_t cEntries, PINTNETDSTTAB *ppDstTab) 1687 { 1688 PINTNETDSTTAB pDstTab; 1689 *ppDstTab = pDstTab = (PINTNETDSTTAB)RTMemAlloc(RT_OFFSETOF(INTNETDSTTAB, aIfs[cEntries])); 1690 if (RT_UNLIKELY(!pDstTab)) 1691 return VERR_NO_MEMORY; 1692 return VINF_SUCCESS; 1693 } 1694 1695 1696 /** 1697 * Ensures that there is space for another interface in the MAC address lookup 1698 * table as well as all the destination tables. 1699 * 1700 * The caller must own the create/open/destroy mutex. 1701 * 1702 * @returns VINF_SUCCESS, VERR_NO_MEMORY or VERR_OUT_OF_RANGE. 1703 * @param pNetwork The network to operate on. 1704 */ 1705 static int intnetR0NetworkEnsureTabSpace(PINTNETNETWORK pNetwork) 1706 { 1707 /* 1708 * The cEntries and cEntriesAllocated members are only updated while 1709 * owning the big mutex, so we only need the spinlock when doing the 1710 * actual table replacing. 1711 */ 1712 PINTNETMACTAB pTab = &pNetwork->MacTab; 1713 int rc = VINF_SUCCESS; 1714 AssertReturn(pTab->cEntries <= pTab->cEntriesAllocated, VERR_INTERNAL_ERROR_2); 1715 if (pTab->cEntries + 1 > pTab->cEntriesAllocated) 1716 { 1717 uint32_t const cAllocated = pTab->cEntriesAllocated + INTNET_GROW_DSTTAB_SIZE; 1718 if (cAllocated <= INTNET_MAX_IFS) 1719 { 1720 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 1721 1722 /* 1723 * Resize the destination tables first, this can be kind of tedious. 1724 */ 1725 for (uint32_t i = 0; i < pTab->cEntries; i++) 1726 { 1727 PINTNETIF pIf = pTab->paEntries[i].pIf; AssertPtr(pIf); 1728 PINTNETDSTTAB pNew; 1729 rc = intnetR0AllocDstTab(cAllocated, &pNew); 1730 if (RT_FAILURE(rc)) 1731 break; 1732 1733 for (;;) 1734 { 1735 PINTNETDSTTAB pOld = pIf->pDstTab; 1736 if ( pOld 1737 && ASMAtomicCmpXchgPtr((void * volatile *)&pIf->pDstTab, pNew, pOld)) 1738 { 1739 RTMemFree(pOld); 1740 break; 1741 } 1742 intnetR0BusyWait(pNetwork, &pIf->cBusy); 1743 } 1744 } 1745 1746 /* 1747 * The trunk. 1748 */ 1749 if ( RT_SUCCESS(rc) 1750 && pNetwork->MacTab.pTrunk) 1751 { 1752 AssertCompileAdjacentMembers(INTNETTRUNKIF, apTaskDstTabs, apIntDstTabs); 1753 PINTNETTRUNKIF pTrunk = pNetwork->MacTab.pTrunk; 1754 PINTNETDSTTAB * const ppEndDstTab = &pTrunk->apIntDstTabs[pTrunk->cIntDstTabs]; 1755 for (PINTNETDSTTAB *ppDstTab = &pTrunk->apTaskDstTabs[0]; 1756 ppDstTab != ppEndDstTab && RT_SUCCESS(rc); 1757 ppDstTab++) 1758 { 1759 PINTNETDSTTAB pNew; 1760 rc = intnetR0AllocDstTab(cAllocated, &pNew); 1761 if (RT_FAILURE(rc)) 1762 break; 1763 1764 for (;;) 1765 { 1766 RTSpinlockAcquireNoInts(pTrunk->hDstTabSpinlock, &Tmp); 1767 void *pvOld = *ppDstTab; 1768 if (pvOld) 1769 *ppDstTab = pNew; 1770 RTSpinlockReleaseNoInts(pTrunk->hDstTabSpinlock, &Tmp); 1771 if (pvOld) 1772 { 1773 RTMemFree(pvOld); 1774 break; 1775 } 1776 intnetR0BusyWait(pNetwork, &pTrunk->cBusy); 1777 } 1778 } 1779 } 1780 1781 /* 1782 * The MAC Address table itself. 1783 */ 1784 if (RT_SUCCESS(rc)) 1785 { 1786 PINTNETMACTABENTRY paNew = (PINTNETMACTABENTRY)RTMemAlloc(sizeof(INTNETMACTABENTRY) * cAllocated); 1787 if (paNew) 1788 { 1789 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 1790 1791 PINTNETMACTABENTRY paOld = pTab->paEntries; 1792 uint32_t i = pTab->cEntries; 1793 while (i-- > 0) 1794 { 1795 paNew[i] = paOld[i]; 1796 1797 paOld[i].fActive = false; 1798 paOld[i].pIf = NULL; 1799 } 1800 1801 pTab->paEntries = paNew; 1802 pTab->cEntriesAllocated = cAllocated; 1803 1804 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 1805 1806 RTMemFree(paOld); 1807 } 1808 else 1809 rc = VERR_NO_MEMORY; 1810 } 1811 } 1812 else 1813 rc = VERR_OUT_OF_RANGE; 1814 } 1815 return rc; 1816 } 1817 1818 1251 1819 1252 1820 … … 1326 1894 case RTNET_DHCP_MT_ACK: 1327 1895 if (intnetR0IPv4AddrIsGood(pDhcp->bp_yiaddr)) 1328 for (PINTNETIF pCur = pNetwork->pIfs; pCur; pCur = pCur->pNext) 1329 if ( pCur->fMacSet 1330 && !memcmp(&pCur->Mac, &pDhcp->bp_chaddr, sizeof(RTMAC))) 1896 { 1897 PINTNETIF pMatchingIf = NULL; 1898 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 1899 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 1900 1901 uint32_t iIf = pNetwork->MacTab.cEntries; 1902 while (iIf-- > 0) 1903 { 1904 PINTNETIF pCur = pNetwork->MacTab.paEntries[iIf].pIf; 1905 if ( intnetR0IfHasMacAddr(pCur) 1906 && !memcmp(&pCur->MacAddr, &pDhcp->bp_chaddr, sizeof(RTMAC))) 1331 1907 { 1332 1908 intnetR0IfAddrCacheDelete(pCur, &pCur->aAddrCache[kIntNetAddrType_IPv4], 1333 1909 (PCRTNETADDRU)&pDhcp->bp_ciaddr, sizeof(RTNETADDRIPV4), "DHCP_MT_ACK"); 1334 intnetR0IfAddrCacheAdd(pCur, &pCur->aAddrCache[kIntNetAddrType_IPv4], 1335 (PCRTNETADDRU)&pDhcp->bp_yiaddr, sizeof(RTNETADDRIPV4), "DHCP_MT_ACK"); 1336 break; 1910 if (!pMatchingIf) 1911 { 1912 pMatchingIf = pCur; 1913 intnetR0BusyIncIf(pMatchingIf); 1914 } 1337 1915 } 1338 break; 1916 } 1917 1918 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 1919 1920 if (pMatchingIf) 1921 { 1922 intnetR0IfAddrCacheAdd(pMatchingIf, &pMatchingIf->aAddrCache[kIntNetAddrType_IPv4], 1923 (PCRTNETADDRU)&pDhcp->bp_yiaddr, sizeof(RTNETADDRIPV4), "DHCP_MT_ACK"); 1924 intnetR0BusyDecIf(pMatchingIf); 1925 } 1926 } 1927 return; 1339 1928 1340 1929 … … 1344 1933 case RTNET_DHCP_MT_RELEASE: 1345 1934 { 1346 for (PINTNETIF pCur = pNetwork->pIfs; pCur; pCur = pCur->pNext) 1347 if ( pCur->fMacSet 1348 && !memcmp(&pCur->Mac, &pDhcp->bp_chaddr, sizeof(RTMAC))) 1935 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 1936 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 1937 1938 uint32_t iIf = pNetwork->MacTab.cEntries; 1939 while (iIf-- > 0) 1940 { 1941 PINTNETIF pCur = pNetwork->MacTab.paEntries[iIf].pIf; 1942 if ( intnetR0IfHasMacAddr(pCur) 1943 && !memcmp(&pCur->MacAddr, &pDhcp->bp_chaddr, sizeof(RTMAC))) 1349 1944 { 1350 1945 intnetR0IfAddrCacheDelete(pCur, &pCur->aAddrCache[kIntNetAddrType_IPv4], … … 1353 1948 (PCRTNETADDRU)&pDhcp->bp_yiaddr, sizeof(RTNETADDRIPV4), "DHCP_MT_RELEASE"); 1354 1949 } 1950 } 1951 1952 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 1355 1953 break; 1356 1954 } … … 1408 2006 1409 2007 /** 1410 * Snoops up source addresses from ARP requests and purge these 1411 * from the addresscaches.2008 * Snoops up source addresses from ARP requests and purge these from the address 2009 * caches. 1412 2010 * 1413 2011 * The purpose of this purging is to get rid of stale addresses. … … 1458 2056 * Delete the source address if it's OK. 1459 2057 */ 1460 if ( ! (pArpIPv4->ar_sha.au8[0] & 1)2058 if ( !intnetR0IsMacAddrMulticast(&pArpIPv4->ar_sha) 1461 2059 && ( pArpIPv4->ar_sha.au16[0] 1462 2060 || pArpIPv4->ar_sha.au16[1] … … 1678 2276 1679 2277 if ( ar_oper == RTNET_ARPOP_REPLY 1680 && ! (pArpIPv4->ar_tha.au8[0] & 1)2278 && !intnetR0IsMacAddrMulticast(&pArpIPv4->ar_tha) 1681 2279 && ( pArpIPv4->ar_tha.au16[0] 1682 2280 || pArpIPv4->ar_tha.au16[1] … … 1686 2284 (PCRTNETADDRU)&pArpIPv4->ar_tpa, sizeof(RTNETADDRIPV4), "if/arp"); 1687 2285 1688 if ( !memcmp(&pArpIPv4->ar_sha, &pIf->Mac , sizeof(RTMAC))2286 if ( !memcmp(&pArpIPv4->ar_sha, &pIf->MacAddr, sizeof(RTMAC)) 1689 2287 && intnetR0IPv4AddrIsGood(pArpIPv4->ar_spa)) 1690 2288 intnetR0IfAddrCacheAdd(pIf, &pIf->aAddrCache[kIntNetAddrType_IPv4], … … 1782 2380 static void intnetR0IfSend(PINTNETIF pIf, PINTNETIF pIfSender, PINTNETSG pSG, PCRTMAC pNewDstMac) 1783 2381 { 1784 // LogFlow(("intnetR0IfSend: pIf=%p:{.hIf=%RX32}\n", pIf, pIf->hIf)); 2382 /* 2383 * Grab the receive/producer lock and copy over the frame. 2384 */ 2385 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 2386 RTSpinlockAcquireNoInts(pIf->hRecvInSpinlock, &Tmp); 1785 2387 int rc = intnetR0RingWriteFrame(&pIf->pIntBuf->Recv, pSG, pNewDstMac); 2388 RTSpinlockReleaseNoInts(pIf->hRecvInSpinlock, &Tmp); 1786 2389 if (RT_SUCCESS(rc)) 1787 2390 { 1788 2391 pIf->cYields = 0; 1789 RTSemEventSignal(pIf-> Event);2392 RTSemEventSignal(pIf->hRecvEvent); 1790 2393 return; 1791 2394 } … … 1793 2396 Log(("intnetR0IfSend: overflow cb=%d hIf=%RX32\n", pSG->cbTotal, pIf->hIf)); 1794 2397 1795 #if 0 /* This is bad stuff now as we're blocking while locking down the network.1796 we really shouldn't delay the network traffic on the host just because1797 some bugger isn't responding. Will have to deal with this in a different1798 manner if required. */1799 /*1800 * Retry a few times, yielding the CPU in between.1801 * But don't let a unresponsive VM harm performance, so give up after a couple of tries.1802 */1803 if ( pIf->fActive1804 && pIf->cYields < 100)1805 {1806 unsigned cYields = 10;1807 #else1808 2398 /* 1809 2399 * Scheduling hack, for unicore machines primarily. … … 1811 2401 if ( pIf->fActive 1812 2402 && pIf->cYields < 4 /* just twice */ 1813 && pIfSender /* but not if it's from the trunk */) 2403 && pIfSender /* but not if it's from the trunk */ 2404 && RTThreadPreemptIsEnabled(NIL_RTTHREAD) 2405 ) 1814 2406 { 1815 2407 unsigned cYields = 2; 1816 #endif1817 2408 while (--cYields > 0) 1818 2409 { 1819 RTSemEventSignal(pIf-> Event);2410 RTSemEventSignal(pIf->hRecvEvent); 1820 2411 RTThreadYield(); 2412 2413 RTSpinlockAcquireNoInts(pIf->hRecvInSpinlock, &Tmp); 1821 2414 rc = intnetR0RingWriteFrame(&pIf->pIntBuf->Recv, pSG, pNewDstMac); 2415 RTSpinlockReleaseNoInts(pIf->hRecvInSpinlock, &Tmp); 1822 2416 if (RT_SUCCESS(rc)) 1823 2417 { 1824 2418 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatYieldsOk); 1825 RTSemEventSignal(pIf-> Event);2419 RTSemEventSignal(pIf->hRecvEvent); 1826 2420 return; 1827 2421 } … … 1833 2427 /* ok, the frame is lost. */ 1834 2428 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatLost); 1835 RTSemEventSignal(pIf-> Event);2429 RTSemEventSignal(pIf->hRecvEvent); 1836 2430 } 1837 2431 … … 1896 2490 * @param pThis The trunk. 1897 2491 * @param pSG The scatter / gather buffer. 1898 * @param fDst The des itination mask.2492 * @param fDst The destination mask. 1899 2493 */ 1900 2494 DECLINLINE(bool) intnetR0TrunkIfCanHandleGsoFrame(PINTNETTRUNKIF pThis, PINTNETSG pSG, uint32_t fDst) … … 1916 2510 * Sends a frame down the trunk. 1917 2511 * 1918 * The caller must own the network mutex, might be abandond temporarily.1919 * The fTrunkLock parameter indicates whether the trunk lock is held.1920 *1921 2512 * @param pThis The trunk. 1922 2513 * @param pNetwork The network the frame is being sent to. 1923 * @param pIfSender The IF sending the frame. Used for MAC address checks in shared MAC mode. 2514 * @param pIfSender The IF sending the frame. Used for MAC address 2515 * checks in shared MAC mode. 1924 2516 * @param fDst The destination flags. 1925 2517 * @param pSG Pointer to the gather list. 1926 * @param fTrunkLocked Whether the caller owns the out-bound trunk lock.1927 2518 */ 1928 2519 static void intnetR0TrunkIfSend(PINTNETTRUNKIF pThis, PINTNETNETWORK pNetwork, PINTNETIF pIfSender, 1929 uint32_t fDst, PINTNETSG pSG , bool fTrunkLocked)2520 uint32_t fDst, PINTNETSG pSG) 1930 2521 { 1931 2522 /* … … 1949 2540 && (fDst & INTNETTRUNKDIR_WIRE)) 1950 2541 { 1951 /* Dispatch it to the host before making changes. */ 2542 /* 2543 * Dispatch it to the host before making changes. 2544 */ 1952 2545 if (fDst & INTNETTRUNKDIR_HOST) 1953 2546 { 1954 2547 Assert(pSG->fFlags & INTNETSG_FLAGS_TEMP); /* make sure copy is forced */ 1955 intnetR0TrunkIfSend(pThis, pNetwork, pIfSender, INTNETTRUNKDIR_HOST, pSG , fTrunkLocked);2548 intnetR0TrunkIfSend(pThis, pNetwork, pIfSender, INTNETTRUNKDIR_HOST, pSG); 1956 2549 fDst &= ~INTNETTRUNKDIR_HOST; 1957 2550 } 1958 2551 2552 /* 2553 * Edit the source address so that it it's the same as the host. 2554 */ 1959 2555 /* ASSUME frame from INTNETR0IfSend! */ 1960 2556 AssertReturnVoid(pSG->cSegsUsed == 1); 1961 2557 AssertReturnVoid(pSG->cbTotal >= sizeof(RTNETETHERHDR)); 1962 AssertReturnVoid(fTrunkLocked);1963 2558 AssertReturnVoid(pIfSender); 1964 2559 PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pSG->aSegs[0].pv; 1965 2560 1966 /* 1967 * Get the host mac address and update the ethernet header. 1968 * 1969 * The reason for caching it in the trunk structure is because 1970 * we cannot take the trunk out-bound semaphore when we make 1971 * edits in the intnetR0TrunkIfPortRecv path. 1972 */ 1973 pThis->pIfPort->pfnGetMacAddress(pThis->pIfPort, &pThis->CachedMac); 1974 if (!memcmp(&pEthHdr->SrcMac, &pIfSender->Mac, sizeof(RTMAC))) 1975 pEthHdr->SrcMac = pThis->CachedMac; 2561 pEthHdr->SrcMac = pThis->MacAddr; 1976 2562 1977 2563 /* … … 1988 2574 */ 1989 2575 PRTNETARPIPV4 pArp = (PRTNETARPIPV4)(pEthHdr + 1); 1990 if (!memcmp(&pArp->ar_sha, &pIfSender->Mac , sizeof(RTMAC)))2576 if (!memcmp(&pArp->ar_sha, &pIfSender->MacAddr, sizeof(RTMAC))) 1991 2577 { 1992 Log6(("tw: ar_sha %.6Rhxs -> %.6Rhxs\n", &pArp->ar_sha, &pThis-> CachedMac));1993 pArp->ar_sha = pThis-> CachedMac;2578 Log6(("tw: ar_sha %.6Rhxs -> %.6Rhxs\n", &pArp->ar_sha, &pThis->MacAddr)); 2579 pArp->ar_sha = pThis->MacAddr; 1994 2580 } 1995 if (!memcmp(&pArp->ar_tha, &pIfSender->Mac , sizeof(RTMAC))) /* just in case... */2581 if (!memcmp(&pArp->ar_tha, &pIfSender->MacAddr, sizeof(RTMAC))) /* just in case... */ 1996 2582 { 1997 Log6(("tw: ar_tha %.6Rhxs -> %.6Rhxs\n", &pArp->ar_tha, &pThis-> CachedMac));1998 pArp->ar_tha = pThis-> CachedMac;2583 Log6(("tw: ar_tha %.6Rhxs -> %.6Rhxs\n", &pArp->ar_tha, &pThis->MacAddr)); 2584 pArp->ar_tha = pThis->MacAddr; 1999 2585 } 2000 2586 } … … 2005 2591 2006 2592 /* 2007 * Temporarily leave the network lock while transmitting the frame. 2008 * 2009 * Note that we're relying on the out-bound lock to serialize threads down 2010 * in INTNETR0IfSend. It's theoretically possible for there to be race now 2011 * because I didn't implement async SG handling yet. Which is why we 2012 * currently require the trunk to be locked, well, one of the reasons. 2013 * 2014 * Another reason is that the intnetR0NetworkSendUnicast code may have to 2015 * call into the trunk interface component to do package switching. 2016 */ 2017 AssertReturnVoid(fTrunkLocked); /* to be removed. */ 2018 2593 * Grab the out-bound lock and send the frame. 2594 */ 2019 2595 int rc; 2020 if ( fTrunkLocked 2021 || intnetR0TrunkIfRetain(pThis)) 2022 { 2023 rc = RTSemFastMutexRelease(pNetwork->FastMutex2); 2024 AssertRC(rc); 2025 if (RT_SUCCESS(rc)) 2026 { 2027 if ( fTrunkLocked 2028 || intnetR0TrunkIfOutLock(pThis)) 2029 { 2030 if ( pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID 2031 || intnetR0TrunkIfCanHandleGsoFrame(pThis, pSG, fDst) ) 2032 rc = pThis->pIfPort->pfnXmit(pThis->pIfPort, pSG, fDst); 2033 else 2034 rc = intnetR0TrunkIfSendGsoFallback(pThis, pSG, fDst); 2035 2036 if (!fTrunkLocked) 2037 intnetR0TrunkIfOutUnlock(pThis); 2038 } 2039 else 2040 { 2041 AssertFailed(); 2042 rc = VERR_SEM_DESTROYED; 2043 } 2044 2045 int rc2 = RTSemFastMutexRequest(pNetwork->FastMutex2); 2046 AssertRC(rc2); 2047 } 2048 2049 if (!fTrunkLocked) 2050 intnetR0TrunkIfRelease(pThis); 2596 if (intnetR0TrunkIfOutLock(pThis)) 2597 { 2598 if ( pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID 2599 || intnetR0TrunkIfCanHandleGsoFrame(pThis, pSG, fDst) ) 2600 rc = pThis->pIfPort->pfnXmit(pThis->pIfPort, pSG, fDst); 2601 else 2602 rc = intnetR0TrunkIfSendGsoFallback(pThis, pSG, fDst); 2603 intnetR0TrunkIfOutUnlock(pThis); 2051 2604 } 2052 2605 else … … 2057 2610 2058 2611 /** @todo failure statistics? */ 2059 Log2(("intnetR0TrunkIfSend: %Rrc fDst=%d\n", rc, fDst)); 2612 Log2(("intnetR0TrunkIfSend: %Rrc fDst=%d\n", rc, fDst)); NOREF(rc); 2060 2613 } 2061 2614 … … 2113 2666 */ 2114 2667 if ( ar_oper == RTNET_ARPOP_REPLY 2115 && !memcmp(&pArpIPv4->ar_tha, &pNetwork-> pTrunkIF->CachedMac, sizeof(RTMAC)))2668 && !memcmp(&pArpIPv4->ar_tha, &pNetwork->MacTab.pTrunk->MacAddr, sizeof(RTMAC))) 2116 2669 { 2117 2670 PINTNETIF pIf = intnetR0NetworkAddrCacheLookupIf(pNetwork, (PCRTNETADDRU)&pArpIPv4->ar_tpa, … … 2119 2672 if (pIf) 2120 2673 { 2121 Log6(("fw: ar_tha %.6Rhxs -> %.6Rhxs\n", &pArpIPv4->ar_tha, &pIf->Mac ));2122 pArpIPv4->ar_tha = pIf->Mac ;2123 if (!memcmp(&pEthHdr->DstMac, &pNetwork-> pTrunkIF->CachedMac, sizeof(RTMAC)))2674 Log6(("fw: ar_tha %.6Rhxs -> %.6Rhxs\n", &pArpIPv4->ar_tha, &pIf->MacAddr)); 2675 pArpIPv4->ar_tha = pIf->MacAddr; 2676 if (!memcmp(&pEthHdr->DstMac, &pNetwork->MacTab.pTrunk->MacAddr, sizeof(RTMAC))) 2124 2677 { 2125 Log6(("fw: DstMac %.6Rhxs -> %.6Rhxs\n", &pEthHdr->DstMac, &pIf->Mac ));2126 pEthHdr->DstMac = pIf->Mac ;2678 Log6(("fw: DstMac %.6Rhxs -> %.6Rhxs\n", &pEthHdr->DstMac, &pIf->MacAddr)); 2679 pEthHdr->DstMac = pIf->MacAddr; 2127 2680 if ((void *)pEthHdr != pSG->aSegs[0].pv) 2128 intnetR0SgWritePart(pSG, RT_OFFSETOF(RTNETETHERHDR, DstMac), sizeof(RTMAC), &pIf->Mac );2681 intnetR0SgWritePart(pSG, RT_OFFSETOF(RTNETETHERHDR, DstMac), sizeof(RTMAC), &pIf->MacAddr); 2129 2682 } 2683 intnetR0BusyDecIf(pIf); 2130 2684 2131 2685 /* Write back the packet if we've been making changes to a buffered copy. */ … … 2229 2783 2230 2784 /** 2231 * Sends a broadcast frame. 2232 * 2233 * The caller must own the network mutex, might be abandond temporarily. 2234 * When pIfSender is not NULL, the caller must also own the trunk semaphore. 2235 * 2236 * @returns true if it's addressed to someone on the network, otherwise false. 2237 * @param pNetwork The network the frame is being sent to. 2238 * @param pIfSender The interface sending the frame. This is NULL if it's the trunk. 2239 * @param fSrc The source flags. This 0 if it's not from the trunk. 2240 * @param pSG Pointer to the gather list. 2241 * @param fTrunkLocked Whether the caller owns the out-bound trunk lock. 2242 * @param pEthHdr Pointer to the ethernet header. 2243 */ 2244 static bool intnetR0NetworkSendBroadcast(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc, 2245 PINTNETSG pSG, bool fTrunkLocked, PRTNETETHERHDR pEthHdr) 2246 { 2785 * Checks if the callers context is okay for sending to the specified 2786 * destinations. 2787 * 2788 * @returns true if it's okay, false if it isn't. 2789 * @param pNetwork The network. 2790 * @param pDstTab The destination table. 2791 */ 2792 DECLINLINE(bool) intnetR0NetworkIsContextOk(PINTNETNETWORK pNetwork, PCINTNETDSTTAB pDstTab) 2793 { 2794 uint32_t const fTrunkDst = pDstTab->fTrunkDst; 2795 if (!fTrunkDst) 2796 return true; 2797 2798 /* ASSUMES: that the trunk won't change its report while we're checking. */ 2799 PINTNETTRUNKIF pTrunk = pDstTab->pTrunk; 2800 if ( ((fTrunkDst & INTNETTRUNKDIR_HOST) && (pTrunk->fHostNoPreempt || !pNetwork->MacTab.fHostActive)) 2801 && ((fTrunkDst & INTNETTRUNKDIR_WIRE) && (pTrunk->fWireNoPreempt || !pNetwork->MacTab.fWireActive)) 2802 ) 2803 return true; 2804 2805 /* ASSUMES: That a preemption test detects HWACCM contexts. (Will work on 2806 non-preemptive systems as well.) */ 2807 if (RTThreadPreemptIsEnabled(NIL_RTTHREAD)) 2808 return true; 2809 return false; 2810 } 2811 2812 2813 /** 2814 * Checks if the callers context is okay for doing a broadcast given the 2815 * specified source. 2816 * 2817 * @returns true if it's okay, false if it isn't. 2818 * @param pNetwork The network. 2819 * @param fSrc The source of the packet. (0 (intnet), 2820 * INTNETTRUNKDIR_HOST or INTNETTRUNKDIR_WIRE). 2821 */ 2822 DECLINLINE(bool) intnetR0NetworkIsContextOkForBroadcast(PINTNETNETWORK pNetwork, uint32_t fSrc) 2823 { 2824 if ( (!pNetwork->MacTab.fHostActive || fSrc == INTNETTRUNKDIR_HOST) 2825 && (!pNetwork->MacTab.fWireActive || fSrc == INTNETTRUNKDIR_WIRE) ) 2826 return true; 2827 2828 /* ASSUMES: That a preemption test detects HWACCM contexts. (Will work on 2829 non-preemptive systems as well.) */ 2830 if (RTThreadPreemptIsEnabled(NIL_RTTHREAD)) 2831 return true; 2832 2833 /* PARANOIA: Grab the spinlock to make sure the trunk structure cannot be 2834 freed while we're touching it. */ 2835 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 2836 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 2837 PINTNETTRUNKIF pTrunk = pNetwork->MacTab.pTrunk; 2838 2839 bool fRc = !pTrunk 2840 || ( (!pNetwork->MacTab.fHostActive || pTrunk->fHostNoPreempt || fSrc == INTNETTRUNKDIR_HOST) 2841 && (!pNetwork->MacTab.fWireActive || pTrunk->fWireNoPreempt || fSrc == INTNETTRUNKDIR_WIRE) ); 2842 2843 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 2844 2845 return fRc; 2846 } 2847 2848 2849 /** 2850 * Check context, edit, snoop and switch a broadcast frame when sharing MAC 2851 * address on the wire. 2852 * 2853 * The caller must hold at least one interface on the network busy to prevent it 2854 * from destructing beath us. 2855 * 2856 * @param pNetwork The network the frame is being sent to. 2857 * @param fSrc The source of the packet. (0 (intnet), 2858 * INTNETTRUNKDIR_HOST or INTNETTRUNKDIR_WIRE). 2859 * @param pIfSender The sender interface, NULL if trunk. Used to 2860 * prevent sending an echo to the sender. 2861 * @param pSG Pointer to the gather list. 2862 * @param pEthHdr Pointer to the ethernet header. 2863 * @param pDstTab The destination output table. 2864 */ 2865 static INTNETSWDECISION intnetR0NetworkSharedMacFixAndSwitchBroadcast(PINTNETNETWORK pNetwork, 2866 uint32_t fSrc, PINTNETIF pIfSender, 2867 PINTNETSG pSG, PRTNETETHERHDR pEthHdr, 2868 PINTNETDSTTAB pDstTab) 2869 { 2870 /* 2871 * Before doing any work here, we need to figure out if we can handle it 2872 * in the current context. The restrictions are solely on the trunk. 2873 * 2874 * Note! Since at least one interface is busy, there won't be any changes 2875 * to the parameters here (unless the trunk changes its capability 2876 * report, which it shouldn't). 2877 */ 2878 if (!intnetR0NetworkIsContextOkForBroadcast(pNetwork, fSrc)) 2879 return INTNETSWDECISION_BAD_CONTEXT; 2880 2247 2881 /* 2248 2882 * Check for ARP packets from the wire since we'll have to make 2249 2883 * modification to them if we're sharing the MAC address with the host. 2250 2884 */ 2251 if ( ( pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)2252 && (fSrc & INTNETTRUNKDIR_WIRE)2253 && RT_BE2H_U16(pEthHdr->EtherType) == RTNET_ETHERTYPE_ARP)2885 if ( (fSrc & INTNETTRUNKDIR_WIRE) 2886 && RT_BE2H_U16(pEthHdr->EtherType) == RTNET_ETHERTYPE_ARP 2887 && pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID) 2254 2888 intnetR0NetworkEditArpFromWire(pNetwork, pSG, pEthHdr); 2255 2889 2256 2890 /* 2257 2891 * Check for DHCP packets from the internal net since we'll have to set 2258 2892 * broadcast flag in DHCP requests if we're sharing the MAC address with 2259 2893 * the host. GSO is not applicable to DHCP traffic. 2260 2894 */ 2261 if ( (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE) 2262 && !fSrc 2895 if ( !fSrc 2263 2896 && RT_BE2H_U16(pEthHdr->EtherType) == RTNET_ETHERTYPE_IPV4 2264 2897 && pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID) … … 2266 2899 2267 2900 /* 2268 * This is a broadcast or multicast address. For the present we treat those2269 * two as the same - investigating multicast is left for later.2270 *2271 * Write the packet to all the interfaces and signal them.2272 */2273 for (PINTNETIF pIf = pNetwork->pIfs; pIf; pIf = pIf->pNext)2274 if (pIf != pIfSender)2275 intnetR0IfSend(pIf, pIfSender, pSG, NULL);2276 2277 /*2278 * Unless the trunk is the origin, broadcast it to both the wire2279 * and the host as well.2280 */2281 PINTNETTRUNKIF pTrunkIf = pNetwork->pTrunkIF;2282 if ( pIfSender2283 && pTrunkIf)2284 intnetR0TrunkIfSend(pTrunkIf, pNetwork, pIfSender, INTNETTRUNKDIR_HOST | INTNETTRUNKDIR_WIRE, pSG, fTrunkLocked);2285 2286 /*2287 2901 * Snoop address info from packet orginating from the trunk connection. 2288 2902 */ 2289 else if ( (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE) 2290 && !pIfSender) 2903 if (fSrc) 2291 2904 { 2292 2905 #ifdef INTNET_WITH_DHCP_SNOOPING … … 2295 2908 && pSG->cbTotal >= sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN 2296 2909 && pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID ) 2297 || (pSG->fFlags & (INTNETSG_FLAGS_ARP_IPV4)) )2910 || (pSG->fFlags & INTNETSG_FLAGS_ARP_IPV4) ) 2298 2911 intnetR0TrunkIfSnoopAddr(pNetwork, pSG, EtherType); 2299 2912 #else 2300 if (pSG->fFlags & (INTNETSG_FLAGS_ARP_IPV4))2913 if (pSG->fFlags & INTNETSG_FLAGS_ARP_IPV4) 2301 2914 intnetR0TrunkIfSnoopArp(pNetwork, pSG); 2302 2915 #endif 2303 2916 } 2304 2917 2305 return false; /* broadcast frames are never dropped */ 2306 } 2307 2308 2309 /** 2310 * Sends a multicast frame. 2311 * 2312 * The caller must own the network mutex, might be abandond temporarily. 2313 * 2314 * @returns true if it's addressed to someone on the network, otherwise false. 2315 * @param pNetwork The network the frame is being sent to. 2316 * @param pIfSender The interface sending the frame. This is NULL if it's the trunk. 2317 * @param fSrc The source flags. This 0 if it's not from the trunk. 2318 * @param pSG Pointer to the gather list. 2319 * @param fTrunkLocked Whether the caller owns the out-bound trunk lock. 2320 * @param pEthHdr Pointer to the ethernet header. 2321 */ 2322 static bool intnetR0NetworkSendMulticast(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc, PINTNETSG pSG, bool fTrunkLocked, PRTNETETHERHDR pEthHdr) 2323 { 2324 /** @todo implement multicast */ 2325 return intnetR0NetworkSendBroadcast(pNetwork, pIfSender, fSrc, pSG, fTrunkLocked, pEthHdr); 2326 } 2327 2328 2329 /** 2330 * Sends a unicast frame using the network layer address instead 2331 * of the link layer one. 2332 * 2333 * This function is only used for frames comming from the write (trunk). 2334 * 2335 * The caller must own the network mutex, might be abandond temporarily. 2918 /* 2919 * Create the broadcast destination table. 2920 */ 2921 return intnetR0NetworkSwitchBroadcast(pNetwork, fSrc, pIfSender, pDstTab); 2922 } 2923 2924 2925 /** 2926 * Check context, snoop and switch a unicast frame using the network layer 2927 * address of the link layer one (when sharing MAC address on the wire). 2928 * 2929 * This function is only used for frames comming from the wire (trunk). 2336 2930 * 2337 2931 * @returns true if it's addressed to someone on the network, otherwise false. 2338 2932 * @param pNetwork The network the frame is being sent to. 2339 2933 * @param pSG Pointer to the gather list. 2340 * @param fTrunkLocked Whether the caller owns the out-bound trunk lock.2341 2934 * @param pEthHdr Pointer to the ethernet header. 2342 */ 2343 static bool intnetR0NetworkSendUnicastWithSharedMac(PINTNETNETWORK pNetwork, PINTNETSG pSG, bool fTrunkLocked, PRTNETETHERHDR pEthHdr) 2935 * @param pDstTab The destination output table. 2936 */ 2937 static INTNETSWDECISION intnetR0NetworkSharedMacFixAndSwitchUnicast(PINTNETNETWORK pNetwork, PINTNETSG pSG, 2938 PRTNETETHERHDR pEthHdr, PINTNETDSTTAB pDstTab) 2344 2939 { 2345 2940 /* … … 2355 2950 { 2356 2951 Log(("intnetshareduni: failed to read ip_dst! cbTotal=%#x\n", pSG->cbTotal)); 2357 return false;2952 return intnetR0NetworkSwitchTrunk(pNetwork, INTNETTRUNKDIR_WIRE, pDstTab); 2358 2953 } 2359 2954 enmAddrType = kIntNetAddrType_IPv4; … … 2367 2962 { 2368 2963 Log(("intnetshareduni: failed to read ip6_dst! cbTotal=%#x\n", pSG->cbTotal)); 2369 return false;2964 return intnetR0NetworkSwitchTrunk(pNetwork, INTNETTRUNKDIR_WIRE, pDstTab); 2370 2965 } 2371 2966 enmAddrType = kIntNetAddrType_IPv6; … … 2380 2975 { 2381 2976 Log(("intnetshareduni: failed to read ipx_dstnet! cbTotal=%#x\n", pSG->cbTotal)); 2382 return false;2977 return intnetR0NetworkSwitchTrunk(pNetwork, INTNETTRUNKDIR_WIRE, pDstTab); 2383 2978 } 2384 2979 enmAddrType = kIntNetAddrType_IPX; … … 2394 2989 Log6(("intnetshareduni: ARP\n")); 2395 2990 /** @todo revisit this broadcasting of unicast ARP frames! */ 2396 return intnetR0NetworkS endBroadcast(pNetwork, NULL, INTNETTRUNKDIR_WIRE, pSG, fTrunkLocked, pEthHdr);2991 return intnetR0NetworkSwitchBroadcast(pNetwork, INTNETTRUNKDIR_WIRE, NULL, pDstTab); 2397 2992 2398 2993 /* 2399 * Unknown packets are sent do all interfaces that are in promiscuous mode.2994 * Unknown packets are sent to the trunk and any promiscuous interfaces. 2400 2995 */ 2401 2996 default: 2402 2997 { 2403 2998 Log6(("intnetshareduni: unknown ethertype=%#x\n", RT_BE2H_U16(pEthHdr->EtherType))); 2404 if (!(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC))) 2405 { 2406 for (PINTNETIF pIf = pNetwork->pIfs; pIf; pIf = pIf->pNext) 2407 if (pIf->fPromiscuous) 2408 { 2409 Log2(("Dst=%.6Rhxs => %.6Rhxs\n", &pEthHdr->DstMac, &pIf->Mac)); 2410 intnetR0IfSend(pIf, NULL, pSG, NULL); 2411 } 2412 } 2413 return false; 2999 return intnetR0NetworkSwitchTrunkAndPromisc(pNetwork, INTNETTRUNKDIR_WIRE, pDstTab); 2414 3000 } 2415 3001 } 2416 3002 2417 3003 /* 2418 * Send it to interfaces with matching network addresses. 2419 */ 2420 bool fExactIntNetRecipient = false; 2421 for (PINTNETIF pIf = pNetwork->pIfs; pIf; pIf = pIf->pNext) 2422 { 2423 bool fIt = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmAddrType], &Addr, cbAddr) >= 0; 2424 if ( fIt 2425 || ( pIf->fPromiscuous 2426 && !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC)))) 2427 { 2428 Log2(("Dst=%.6Rhxs => %.6Rhxs\n", &pEthHdr->DstMac, &pIf->Mac)); 2429 fExactIntNetRecipient |= fIt; 2430 intnetR0IfSend(pIf, NULL, pSG, fIt ? &pIf->Mac : NULL); 2431 } 2432 } 3004 * Do level-3 switching. 3005 */ 3006 INTNETSWDECISION enmSwDecision = intnetR0NetworkSwitchLevel3(pNetwork, &pEthHdr->DstMac, 3007 enmAddrType, &Addr, cbAddr, 3008 INTNETTRUNKDIR_WIRE, pDstTab); 2433 3009 2434 3010 #ifdef INTNET_WITH_DHCP_SNOOPING … … 2442 3018 #endif /* INTNET_WITH_DHCP_SNOOPING */ 2443 3019 2444 return fExactIntNetRecipient; 2445 } 2446 2447 2448 /** 2449 * Sends a unicast frame. 2450 * 2451 * The caller must own the network mutex, might be abandond temporarily. 2452 * 2453 * @returns true if it's addressed to someone on the network, otherwise false. 3020 return enmSwDecision; 3021 } 3022 3023 3024 /** 3025 * Release all the interfaces in the destination table when we realize that 3026 * we're in a context where we cannot get the job done. 3027 * 3028 * @param pNetwork The network. 3029 * @param pDstTab The destination table. 3030 */ 3031 static void intnetR0NetworkReleaseDstTab(PINTNETNETWORK pNetwork, PINTNETDSTTAB pDstTab) 3032 { 3033 /* The trunk interface. */ 3034 if (pDstTab->fTrunkDst) 3035 { 3036 PINTNETTRUNKIF pTrunk = pDstTab->pTrunk; 3037 intnetR0BusyDec(pNetwork, &pTrunk->cBusy); 3038 pDstTab->pTrunk = NULL; 3039 pDstTab->fTrunkDst = 0; 3040 } 3041 3042 /* Regular interfaces. */ 3043 uint32_t iIf = pDstTab->cIfs; 3044 while (iIf-- > 0) 3045 { 3046 PINTNETIF pIf = pDstTab->aIfs[iIf].pIf; 3047 intnetR0BusyDecIf(pIf); 3048 pDstTab->aIfs[iIf].pIf = NULL; 3049 } 3050 pDstTab->cIfs = 0; 3051 } 3052 3053 3054 /** 3055 * Deliver the frame to the interfaces specified in the destination table. 3056 * 3057 * @param pNetwork The network. 3058 * @param pDstTab The destination table. 3059 * @param pSG The frame to send. 3060 * @param pIfSender The sender interface. NULL if it origined via 3061 * the trunk. 3062 */ 3063 static void intnetR0NetworkDeliver(PINTNETNETWORK pNetwork, PINTNETDSTTAB pDstTab, PINTNETSG pSG, PINTNETIF pIfSender) 3064 { 3065 /* 3066 * Trunk first so we don't wast any more time before hitting the wire. 3067 * 3068 * Note! The switching functions will include the trunk even when the frame 3069 * source is the trunk. This is because we need it to figure out 3070 * whether the other half of the trunk should see the frame or not 3071 * and let the caller know. 3072 * 3073 * So, we'll ignore trunk sends here if the frame origin is 3074 * INTNETTRUNKSWPORT::pfnRecv. 3075 */ 3076 if (pDstTab->fTrunkDst) 3077 { 3078 PINTNETTRUNKIF pTrunk = pDstTab->pTrunk; 3079 if (pIfSender) 3080 intnetR0TrunkIfSend(pTrunk, pNetwork, pIfSender, pDstTab->fTrunkDst, pSG); 3081 intnetR0BusyDec(pNetwork, &pTrunk->cBusy); 3082 pDstTab->pTrunk = NULL; 3083 pDstTab->fTrunkDst = 0; 3084 } 3085 3086 /* 3087 * Do the interfaces. 3088 */ 3089 uint32_t iIf = pDstTab->cIfs; 3090 while (iIf-- > 0) 3091 { 3092 PINTNETIF pIf = pDstTab->aIfs[iIf].pIf; 3093 intnetR0IfSend(pIf, pIfSender, pSG, 3094 pDstTab->aIfs[iIf].fReplaceDstMac ? &pIf->MacAddr: NULL); 3095 intnetR0BusyDecIf(pIf); 3096 pDstTab->aIfs[iIf].pIf = NULL; 3097 } 3098 pDstTab->cIfs = 0; 3099 } 3100 3101 3102 /** 3103 * Sends a frame. 3104 * 3105 * This function will distribute the frame to the interfaces it is addressed to. 3106 * It will also update the MAC address of the sender. 3107 * 3108 * The caller must own the network mutex. 3109 * 3110 * @returns The switching decision. 2454 3111 * @param pNetwork The network the frame is being sent to. 2455 3112 * @param pIfSender The interface sending the frame. This is NULL if it's the trunk. 2456 3113 * @param fSrc The source flags. This 0 if it's not from the trunk. 2457 3114 * @param pSG Pointer to the gather list. 2458 * @param fTrunkLocked Whether the caller owns the out-bound trunk lock. 2459 * @param pEthHdr Pointer to the ethernet header. 2460 */ 2461 static bool intnetR0NetworkSendUnicast(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc, PINTNETSG pSG, bool fTrunkLocked, PCRTNETETHERHDR pEthHdr) 2462 { 2463 /* 2464 * Only send to the interfaces with matching a MAC address. 2465 */ 2466 bool fExactIntNetRecipient = false; 2467 for (PINTNETIF pIf = pNetwork->pIfs; pIf; pIf = pIf->pNext) 2468 { 2469 bool fIt = false; 2470 if ( ( !pIf->fMacSet 2471 || (fIt = !memcmp(&pIf->Mac, &pEthHdr->DstMac, sizeof(pIf->Mac))) ) 2472 || ( pIf->fPromiscuous 2473 && !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC)) 2474 && pIf != pIfSender /* promiscuous mode: omit the sender */)) 2475 { 2476 Log2(("Dst=%.6Rhxs => %.6Rhxs\n", &pEthHdr->DstMac, &pIf->Mac)); 2477 fExactIntNetRecipient |= fIt; 2478 intnetR0IfSend(pIf, pIfSender, pSG, NULL); 2479 } 2480 } 2481 2482 /* 2483 * Send it to the trunk? 2484 * If we didn't find the recipient on the internal network the 2485 * frame will hit the wire. 2486 */ 2487 uint32_t fDst = 0; 2488 PINTNETTRUNKIF pTrunkIf = pNetwork->pTrunkIF; 2489 if ( pIfSender 2490 && pTrunkIf 2491 && pTrunkIf->pIfPort) 2492 { 2493 Assert(!fSrc); 2494 2495 /* promiscuous checks first as they are cheaper than pfnIsHostMac. */ 2496 if ( pTrunkIf->fWirePromiscuous 2497 && !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC | INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_WIRE | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_WIRE)) ) 2498 fDst |= INTNETTRUNKDIR_WIRE; 2499 if ( !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC | INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_HOST | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_HOST)) 2500 && pTrunkIf->pIfPort->pfnIsPromiscuous(pTrunkIf->pIfPort) ) 2501 fDst |= INTNETTRUNKDIR_HOST; 2502 2503 if ( fDst != (INTNETTRUNKDIR_HOST | INTNETTRUNKDIR_WIRE) 2504 && !fExactIntNetRecipient /* if you have duplicate mac addresses, you're screwed. */ ) 2505 { 2506 if (pTrunkIf->pIfPort->pfnIsHostMac(pTrunkIf->pIfPort, &pEthHdr->DstMac)) 2507 fDst |= INTNETTRUNKDIR_HOST; 2508 else 2509 fDst |= INTNETTRUNKDIR_WIRE; 2510 } 2511 2512 if (fDst) 2513 intnetR0TrunkIfSend(pTrunkIf, pNetwork, pIfSender, fDst, pSG, fTrunkLocked); 2514 } 2515 2516 /* log it */ 2517 if ( !fExactIntNetRecipient 2518 && !fDst 2519 && ( (pEthHdr->DstMac.au8[0] == 0x08 && pEthHdr->DstMac.au8[1] == 0x00 && pEthHdr->DstMac.au8[2] == 0x27) 2520 || (pEthHdr->SrcMac.au8[0] == 0x08 && pEthHdr->SrcMac.au8[1] == 0x00 && pEthHdr->SrcMac.au8[2] == 0x27))) 2521 Log2(("Dst=%.6Rhxs ??\n", &pEthHdr->DstMac)); 2522 2523 return fExactIntNetRecipient; 2524 } 2525 2526 2527 /** 2528 * Sends a frame. 2529 * 2530 * This function will distribute the frame to the interfaces it is addressed to. 2531 * It will also update the MAC address of the sender. 2532 * 2533 * The caller must own the network mutex. 2534 * 2535 * @returns true if it's addressed to someone on the network, otherwise false. 2536 * @param pNetwork The network the frame is being sent to. 2537 * @param pIfSender The interface sending the frame. This is NULL if it's the trunk. 2538 * @param fSrc The source flags. This 0 if it's not from the trunk. 2539 * @param pSG Pointer to the gather list. 2540 * @param fTrunkLocked Whether the caller owns the out-bound trunk lock. 2541 */ 2542 static bool intnetR0NetworkSend(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc, PINTNETSG pSG, bool fTrunkLocked) 2543 { 2544 bool fRc = false; 2545 3115 * @param pDstTab The destination table to use. 3116 */ 3117 static INTNETSWDECISION intnetR0NetworkSend(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc, 3118 PINTNETSG pSG, PINTNETDSTTAB pDstTab) 3119 { 2546 3120 /* 2547 3121 * Assert reality. … … 2555 3129 Assert(pSG->cSegsUsed <= pSG->cSegsAlloc); 2556 3130 if (pSG->cbTotal < sizeof(RTNETETHERHDR)) 2557 return fRc;3131 return INTNETSWDECISION_INVALID; 2558 3132 2559 3133 /* … … 2564 3138 EthHdr = *(PCRTNETETHERHDR)pSG->aSegs[0].pv; 2565 3139 else if (!intnetR0SgReadPart(pSG, 0, sizeof(EthHdr), &EthHdr)) 2566 return false;3140 return INTNETSWDECISION_INVALID; 2567 3141 if ( (EthHdr.DstMac.au8[0] == 0x08 && EthHdr.DstMac.au8[1] == 0x00 && EthHdr.DstMac.au8[2] == 0x27) 2568 3142 || (EthHdr.SrcMac.au8[0] == 0x08 && EthHdr.SrcMac.au8[1] == 0x00 && EthHdr.SrcMac.au8[2] == 0x27) … … 2575 3149 2576 3150 /* 2577 * Inspect the header updating the mac address of the sender in the process. 2578 */ 2579 if ( pIfSender 2580 && memcmp(&EthHdr.SrcMac, &pIfSender->Mac, sizeof(pIfSender->Mac))) 2581 { 2582 /** @todo stats */ 2583 Log2(("IF MAC: %.6Rhxs -> %.6Rhxs\n", &pIfSender->Mac, &EthHdr.SrcMac)); 2584 pIfSender->Mac = EthHdr.SrcMac; 2585 pIfSender->fMacSet = true; 2586 } 2587 2588 /* 2589 * Distribute the frame. 2590 */ 2591 if ( EthHdr.DstMac.au16[0] == 0xffff /* broadcast address. */ 2592 && EthHdr.DstMac.au16[1] == 0xffff 2593 && EthHdr.DstMac.au16[2] == 0xffff) 2594 fRc = intnetR0NetworkSendBroadcast(pNetwork, pIfSender, fSrc, pSG, fTrunkLocked, &EthHdr); 2595 else if (RT_UNLIKELY(EthHdr.DstMac.au8[0] & 1)) /* multicast address */ 2596 fRc = intnetR0NetworkSendMulticast(pNetwork, pIfSender, fSrc, pSG, fTrunkLocked, &EthHdr); 2597 else if ( !(pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE) 2598 || !(fSrc & INTNETTRUNKDIR_WIRE)) 2599 fRc = intnetR0NetworkSendUnicast(pNetwork, pIfSender, fSrc, pSG, fTrunkLocked, &EthHdr); 3151 * Learn the MAC address of the sender. No re-learning as the interface 3152 * user will normally tell us the right MAC address. 3153 */ 3154 if (RT_UNLIKELY( pIfSender 3155 && !pIfSender->fMacSet 3156 && memcmp(&EthHdr.SrcMac, &pIfSender->MacAddr, sizeof(pIfSender->MacAddr)) 3157 && !intnetR0IsMacAddrMulticast(&EthHdr.SrcMac) 3158 )) 3159 { 3160 Log2(("IF MAC: %.6Rhxs -> %.6Rhxs\n", &pIfSender->MacAddr, &EthHdr.SrcMac)); 3161 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 3162 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 3163 3164 PINTNETMACTABENTRY pIfEntry = intnetR0NetworkFindMacAddrEntry(pNetwork, pIfSender); 3165 if (pIfEntry) 3166 pIfEntry->MacAddr = EthHdr.SrcMac; 3167 pIfSender->MacAddr = EthHdr.SrcMac; 3168 3169 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 3170 } 3171 3172 /* 3173 * Deal with MAC address sharing as that may required editing of the 3174 * packets before we dispatch them anywhere. 3175 */ 3176 INTNETSWDECISION enmSwDecision; 3177 if (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE) 3178 { 3179 if (intnetR0IsMacAddrMulticast(&EthHdr.DstMac)) 3180 enmSwDecision = intnetR0NetworkSharedMacFixAndSwitchBroadcast(pNetwork, fSrc, pIfSender, pSG, &EthHdr, pDstTab); 3181 else if (fSrc & INTNETTRUNKDIR_WIRE) 3182 enmSwDecision = intnetR0NetworkSharedMacFixAndSwitchUnicast(pNetwork, pSG, &EthHdr, pDstTab); 3183 else 3184 enmSwDecision = intnetR0NetworkSwitchUnicast(pNetwork, fSrc, pIfSender, &EthHdr.DstMac, pDstTab); 3185 } 3186 else if (intnetR0IsMacAddrMulticast(&EthHdr.DstMac)) 3187 enmSwDecision = intnetR0NetworkSwitchBroadcast(pNetwork, fSrc, pIfSender, pDstTab); 2600 3188 else 2601 fRc = intnetR0NetworkSendUnicastWithSharedMac(pNetwork, pSG, fTrunkLocked, &EthHdr); 2602 return fRc; 3189 enmSwDecision = intnetR0NetworkSwitchUnicast(pNetwork, fSrc, pIfSender, &EthHdr.DstMac, pDstTab); 3190 3191 /* 3192 * Deliver to the destinations if we can. 3193 */ 3194 if (enmSwDecision != INTNETSWDECISION_BAD_CONTEXT) 3195 { 3196 if (intnetR0NetworkIsContextOk(pNetwork, pDstTab)) 3197 intnetR0NetworkDeliver(pNetwork, pDstTab, pSG, pIfSender); 3198 else 3199 { 3200 intnetR0NetworkReleaseDstTab(pNetwork, pDstTab); 3201 enmSwDecision = INTNETSWDECISION_BAD_CONTEXT; 3202 } 3203 } 3204 3205 return enmSwDecision; 2603 3206 } 2604 3207 … … 2607 3210 * Sends one or more frames. 2608 3211 * 2609 * The function will first the frame which is passed as the optional 2610 * arguments pvFrame and cbFrame. These are optional since it also 2611 * possible to chain together one or more frames in the send buffer 2612 * which the function will process after considering it's arguments. 3212 * The function will first the frame which is passed as the optional arguments 3213 * pvFrame and cbFrame. These are optional since it also possible to chain 3214 * together one or more frames in the send buffer which the function will 3215 * process after considering it's arguments. 3216 * 3217 * The caller is responsible for making sure that there are no concurrent calls 3218 * to this method (with the same handle). 2613 3219 * 2614 3220 * @returns VBox status code. … … 2630 3236 2631 3237 /* 2632 * Lock the network. If there is a trunk retain it and grab its 2633 * out-bound lock (this requires leaving the network lock first). 2634 * Grabbing the out-bound lock here simplifies things quite a bit 2635 * later on, so while this is excessive and a bit expensive it's 2636 * not worth caring about right now. 2637 */ 3238 * Make sure we've got a network. 3239 */ 3240 int rc = VINF_SUCCESS; 3241 intnetR0BusyIncIf(pIf); 2638 3242 PINTNETNETWORK pNetwork = pIf->pNetwork; 2639 int rc = RTSemFastMutexRequest(pNetwork->FastMutex2); 2640 if (RT_FAILURE(rc)) 2641 { 2642 intnetR0IfRelease(pIf, pSession); 2643 return rc; 2644 } 2645 PINTNETTRUNKIF pTrunkIf = intnetR0TrunkIfRetain(pNetwork->pTrunkIF); 2646 if (pTrunkIf) 2647 { 2648 RTSemFastMutexRelease(pIf->pNetwork->FastMutex2); 2649 2650 if (!intnetR0TrunkIfOutLock(pTrunkIf)) 3243 if (RT_LIKELY(pNetwork)) 3244 { 3245 /* 3246 * Grab the destination table. 3247 */ 3248 PINTNETDSTTAB pDstTab = (PINTNETDSTTAB)ASMAtomicXchgPtr((void * volatile *)&pIf->pDstTab, NULL); 3249 if (RT_LIKELY(pDstTab)) 2651 3250 { 2652 intnetR0TrunkIfRelease(pTrunkIf); 2653 intnetR0IfRelease(pIf, pSession); 2654 return VERR_SEM_DESTROYED; 3251 /* 3252 * Process the send buffer. 3253 */ 3254 INTNETSWDECISION enmSwDecision = INTNETSWDECISION_BROADCAST; 3255 INTNETSG Sg; /** @todo this will have to be changed if we're going to use async sending 3256 * with buffer sharing for some OS or service. Darwin copies everything so 3257 * I won't bother allocating and managing SGs rigth now. Sorry. */ 3258 PINTNETHDR pHdr; 3259 while ((pHdr = INTNETRingGetNextFrameToRead(&pIf->pIntBuf->Send)) != NULL) 3260 { 3261 uint16_t const u16Type = pHdr->u16Type; 3262 if (u16Type == INTNETHDR_TYPE_FRAME) 3263 { 3264 /* Send regular frame. */ 3265 void *pvCurFrame = INTNETHdrGetFramePtr(pHdr, pIf->pIntBuf); 3266 INTNETSgInitTemp(&Sg, pvCurFrame, pHdr->cbFrame); 3267 if (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE) 3268 intnetR0IfSnoopAddr(pIf, (uint8_t *)pvCurFrame, pHdr->cbFrame, false /*fGso*/, (uint16_t *)&Sg.fFlags); 3269 enmSwDecision = intnetR0NetworkSend(pNetwork, pIf, 0 /*fSrc*/, &Sg, pDstTab); 3270 } 3271 else if (u16Type == INTNETHDR_TYPE_GSO) 3272 { 3273 /* Send GSO frame if sane. */ 3274 PPDMNETWORKGSO pGso = INTNETHdrGetGsoContext(pHdr, pIf->pIntBuf); 3275 uint32_t cbFrame = pHdr->cbFrame - sizeof(*pGso); 3276 if (RT_LIKELY(PDMNetGsoIsValid(pGso, pHdr->cbFrame, cbFrame))) 3277 { 3278 void *pvCurFrame = pGso + 1; 3279 INTNETSgInitTempGso(&Sg, pvCurFrame, cbFrame, pGso); 3280 if (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE) 3281 intnetR0IfSnoopAddr(pIf, (uint8_t *)pvCurFrame, cbFrame, true /*fGso*/, (uint16_t *)&Sg.fFlags); 3282 enmSwDecision = intnetR0NetworkSend(pNetwork, pIf, 0 /*fSrc*/, &Sg, pDstTab); 3283 } 3284 else 3285 { 3286 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatBadFrames); /* ignore */ 3287 enmSwDecision = INTNETSWDECISION_DROP; 3288 } 3289 } 3290 /* Unless it's a padding frame, we're getting babble from the producer. */ 3291 else 3292 { 3293 if (u16Type != INTNETHDR_TYPE_PADDING) 3294 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatBadFrames); /* ignore */ 3295 enmSwDecision = INTNETSWDECISION_DROP; 3296 } 3297 if (enmSwDecision == INTNETSWDECISION_BAD_CONTEXT) 3298 { 3299 rc = VERR_TRY_AGAIN; 3300 break; 3301 } 3302 3303 /* Skip to the next frame. */ 3304 INTNETRingSkipFrame(&pIf->pIntBuf->Send); 3305 } 3306 3307 /* 3308 * Put back the destination table. 3309 */ 3310 Assert(!pIf->pDstTab); 3311 ASMAtomicWritePtr((void * volatile *)&pIf->pDstTab, pDstTab); 2655 3312 } 2656 2657 rc = RTSemFastMutexRequest(pNetwork->FastMutex2); 2658 if (RT_FAILURE(rc)) 2659 { 2660 intnetR0TrunkIfOutUnlock(pTrunkIf); 2661 intnetR0TrunkIfRelease(pTrunkIf); 2662 intnetR0IfRelease(pIf, pSession); 2663 return rc; 2664 } 2665 } 2666 2667 INTNETSG Sg; /** @todo this will have to be changed if we're going to use async sending 2668 * with buffer sharing for some OS or service. Darwin copies everything so 2669 * I won't bother allocating and managing SGs rigth now. Sorry. */ 2670 2671 /* 2672 * Process the send buffer. 2673 */ 2674 PINTNETHDR pHdr; 2675 while ((pHdr = INTNETRingGetNextFrameToRead(&pIf->pIntBuf->Send)) != NULL) 2676 { 2677 uint16_t const u16Type = pHdr->u16Type; 2678 if (u16Type == INTNETHDR_TYPE_FRAME) 2679 { 2680 /* Send regular frame. */ 2681 void *pvCurFrame = INTNETHdrGetFramePtr(pHdr, pIf->pIntBuf); 2682 INTNETSgInitTemp(&Sg, pvCurFrame, pHdr->cbFrame); 2683 if (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE) 2684 intnetR0IfSnoopAddr(pIf, (uint8_t *)pvCurFrame, pHdr->cbFrame, false /*fGso*/, (uint16_t *)&Sg.fFlags); 2685 intnetR0NetworkSend(pNetwork, pIf, 0, &Sg, !!pTrunkIf); 2686 } 2687 else if (u16Type == INTNETHDR_TYPE_GSO) 2688 { 2689 /* Send GSO frame if sane*/ 2690 PPDMNETWORKGSO pGso = INTNETHdrGetGsoContext(pHdr, pIf->pIntBuf); 2691 uint32_t cbFrame = pHdr->cbFrame - sizeof(*pGso); 2692 if (RT_LIKELY(PDMNetGsoIsValid(pGso, pHdr->cbFrame, cbFrame))) 2693 { 2694 void *pvCurFrame = pGso + 1; 2695 INTNETSgInitTempGso(&Sg, pvCurFrame, cbFrame, pGso); 2696 if (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE) 2697 intnetR0IfSnoopAddr(pIf, (uint8_t *)pvCurFrame, cbFrame, true /*fGso*/, (uint16_t *)&Sg.fFlags); 2698 intnetR0NetworkSend(pNetwork, pIf, 0, &Sg, !!pTrunkIf); 2699 } 2700 else 2701 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatBadFrames); /* ignore */ 2702 } 2703 /* Unless it's a padding frame, we're getting babble from the producer. */ 2704 else if (u16Type != INTNETHDR_TYPE_PADDING) 2705 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatBadFrames); /* ignore */ 2706 2707 /* Skip to the next frame. */ 2708 INTNETRingSkipFrame(&pIf->pIntBuf->Send); 2709 } 2710 2711 /* 2712 * Release the semaphore(s) and release references. 2713 */ 2714 rc = RTSemFastMutexRelease(pNetwork->FastMutex2); 2715 if (pTrunkIf) 2716 { 2717 intnetR0TrunkIfOutUnlock(pTrunkIf); 2718 intnetR0TrunkIfRelease(pTrunkIf); 2719 } 2720 3313 else 3314 rc = VERR_INTERNAL_ERROR_4; 3315 } 3316 else 3317 rc = VERR_INTERNAL_ERROR_3; 3318 3319 /* 3320 * Release the interface. 3321 */ 3322 intnetR0BusyDecIf(pIf); 2721 3323 intnetR0IfRelease(pIf, pSession); 2722 3324 return rc; … … 2768 3370 * allocating the buffer. 2769 3371 */ 2770 int rc = RTSem FastMutexRequest(pIf->pNetwork->FastMutex2);3372 int rc = RTSemMutexRequest(pIntNet->hMtxCreateOpenDestroy, RT_INDEFINITE_WAIT); 2771 3373 if (RT_SUCCESS(rc)) 2772 3374 { 2773 3375 *ppRing3Buf = pIf->pIntBufR3; 2774 rc = RTSemFastMutexRelease(pIf->pNetwork->FastMutex2); 3376 3377 rc = RTSemMutexRelease(pIntNet->hMtxCreateOpenDestroy); 2775 3378 } 2776 3379 … … 2824 3427 * ASSUMES that the handle isn't closed while we're here. 2825 3428 */ 2826 int rc = RTSem FastMutexRequest(pIf->pNetwork->FastMutex2);3429 int rc = RTSemMutexRequest(pIntNet->hMtxCreateOpenDestroy, RT_INDEFINITE_WAIT); 2827 3430 if (RT_SUCCESS(rc)) 2828 3431 { 2829 3432 *ppRing0Buf = pIf->pIntBuf; 2830 3433 2831 rc = RTSem FastMutexRelease(pIf->pNetwork->FastMutex2);3434 rc = RTSemMutexRelease(pIntNet->hMtxCreateOpenDestroy); 2832 3435 } 2833 3436 intnetR0IfRelease(pIf, pSession); … … 2902 3505 2903 3506 /* 2904 * Grab the network semaphore and make the change. 2905 */ 2906 int rc; 3507 * Get the network, take the address spinlock, and make the change. 3508 * Paranoia^2: Mark ourselves busy to prevent anything from being destroyed. 3509 */ 3510 int rc = VINF_SUCCESS; 3511 intnetR0BusyIncIf(pIf); 2907 3512 PINTNETNETWORK pNetwork = pIf->pNetwork; 2908 3513 if (pNetwork) 2909 3514 { 2910 rc = RTSemFastMutexRequest(pNetwork->FastMutex2); 2911 if (RT_SUCCESS(rc)) 3515 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 3516 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 3517 3518 if (pIf->fPromiscuous != fPromiscuous) 2912 3519 { 2913 if (pIf->fPromiscuous != fPromiscuous)2914 {2915 Log(("INTNETR0IfSetPromiscuousMode: hIf=%RX32: Changed from %d -> %d\n",2916 hIf, !fPromiscuous, !!fPromiscuous)); 2917 ASMAtomicUoWriteBool(&pIf->fPromiscuous, fPromiscuous);2918 }2919 2920 rc = RTSemFastMutexRelease(pNetwork->FastMutex2);3520 Log(("INTNETR0IfSetPromiscuousMode: hIf=%RX32: Changed from %d -> %d\n", 3521 hIf, !fPromiscuous, !!fPromiscuous)); 3522 ASMAtomicUoWriteBool(&pIf->fPromiscuous, fPromiscuous); 3523 3524 PINTNETMACTABENTRY pEntry = intnetR0NetworkFindMacAddrEntry(pNetwork, pIf); Assert(pEntry); 3525 if (RT_LIKELY(pEntry)) 3526 pEntry->fPromiscuous = fPromiscuous; 3527 pIf->fPromiscuous = fPromiscuous; 2921 3528 } 3529 3530 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 2922 3531 } 2923 3532 else 2924 3533 rc = VERR_WRONG_ORDER; 2925 3534 3535 intnetR0BusyDecIf(pIf); 2926 3536 intnetR0IfRelease(pIf, pSession); 2927 3537 return rc; … … 2971 3581 2972 3582 /* 2973 * Grab the network semaphore and make the change. 2974 */ 2975 int rc; 3583 * Get the network, take the address spinlock, and make the change. 3584 * Paranoia^2: Mark ourselves busy to prevent anything from being destroyed. 3585 */ 3586 int rc = VINF_SUCCESS; 3587 intnetR0BusyIncIf(pIf); 2976 3588 PINTNETNETWORK pNetwork = pIf->pNetwork; 2977 3589 if (pNetwork) 2978 3590 { 2979 rc = RTSemFastMutexRequest(pNetwork->FastMutex2); 2980 if (RT_SUCCESS(rc)) 3591 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 3592 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 3593 3594 if (memcmp(&pIf->MacAddr, pMac, sizeof(pIf->MacAddr))) 2981 3595 { 2982 if (memcmp(&pIf->Mac, pMac, sizeof(pIf->Mac))) 2983 { 2984 Log(("INTNETR0IfSetMacAddress: hIf=%RX32: Changed from %.6Rhxs -> %.6Rhxs\n", 2985 hIf, &pIf->Mac, pMac)); 2986 pIf->Mac = *pMac; 2987 pIf->fMacSet = true; 2988 } 2989 2990 rc = RTSemFastMutexRelease(pNetwork->FastMutex2); 3596 Log(("INTNETR0IfSetMacAddress: hIf=%RX32: Changed from %.6Rhxs -> %.6Rhxs\n", 3597 hIf, &pIf->MacAddr, pMac)); 3598 3599 PINTNETMACTABENTRY pEntry = intnetR0NetworkFindMacAddrEntry(pNetwork, pIf); Assert(pEntry); 3600 if (RT_LIKELY(pEntry)) 3601 pEntry->MacAddr = *pMac; 3602 pIf->MacAddr = *pMac; 3603 pIf->fMacSet = true; 2991 3604 } 3605 3606 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 2992 3607 } 2993 3608 else 2994 3609 rc = VERR_WRONG_ORDER; 2995 3610 3611 intnetR0BusyDecIf(pIf); 2996 3612 intnetR0IfRelease(pIf, pSession); 2997 3613 return rc; … … 3016 3632 3017 3633 /** 3018 * Worker for intnetR0IfSetActive .3634 * Worker for intnetR0IfSetActive and intnetR0IfDestruct. 3019 3635 * 3020 3636 * This function will update the active interface count on the network and 3021 * activate or deactivate the trunk connection if necessary. Note that in3637 * activate or deactivate the trunk connection if necessary. Note that in 3022 3638 * order to do this it is necessary to abandond the network semaphore. 3023 3639 * … … 3034 3650 3035 3651 /* 3036 * If we've got a trunk, lock it now in case we need to call out, and 3037 * then lock the network. 3038 */ 3039 PINTNETTRUNKIF pTrunkIf = pNetwork->pTrunkIF; 3040 if (pTrunkIf && !intnetR0TrunkIfOutLock(pTrunkIf)) 3041 return VERR_SEM_DESTROYED; 3042 3043 int rc = RTSemFastMutexRequest(pNetwork->FastMutex2); AssertRC(rc); 3044 if (RT_SUCCESS(rc)) 3045 { 3046 bool fNetworkLocked = true; 3047 3048 /* 3049 * Make the change if necessary. 3050 */ 3051 if (pIf->fActive != fActive) 3652 * The address spinlock of the network protects the variables, while 3653 * the out-bound trunk semaphore protects the pfnSetActive call. 3654 * Try grab both of them in case we have to make a change. 3655 */ 3656 int rcTrunkLock = VERR_SEM_DESTROYED; 3657 PINTNETTRUNKIF pTrunk = pNetwork->MacTab.pTrunk; 3658 if (pTrunk && intnetR0TrunkIfOutLock(pTrunk)) 3659 rcTrunkLock = VINF_SUCCESS; 3660 3661 bool fTellTrunk = false; 3662 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 3663 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 3664 3665 /* 3666 * Do the update. 3667 */ 3668 if (pIf->fActive != fActive) 3669 { 3670 PINTNETMACTABENTRY pEntry = intnetR0NetworkFindMacAddrEntry(pNetwork, pIf); Assert(pEntry); 3671 if (RT_LIKELY(pEntry)) 3052 3672 { 3053 pIf->fActive = fActive; 3054 3055 uint32_t const cActiveIFs = pNetwork->cActiveIFs; 3056 Assert((int32_t)cActiveIFs + (fActive ? 1 : -1) >= 0); 3057 pNetwork->cActiveIFs += fActive ? 1 : -1; 3058 3059 if ( pTrunkIf 3060 && ( !pNetwork->cActiveIFs 3061 || !cActiveIFs)) 3673 pEntry->fActive = fActive; 3674 pIf->fActive = fActive; 3675 3676 if (fActive) 3062 3677 { 3063 /* 3064 * We'll have to change the trunk status, so, leave 3065 * the network semaphore so we don't create any deadlocks. 3066 */ 3067 int rc2 = RTSemFastMutexRelease(pNetwork->FastMutex2); AssertRC(rc2); 3068 fNetworkLocked = false; 3069 3070 if (pTrunkIf->pIfPort) 3071 pTrunkIf->pIfPort->pfnSetActive(pTrunkIf->pIfPort, fActive); 3678 pNetwork->cActiveIFs++; 3679 fTellTrunk = pNetwork->cActiveIFs == 1; 3680 } 3681 else 3682 { 3683 pNetwork->cActiveIFs--; 3684 fTellTrunk = pNetwork->cActiveIFs == 0; 3072 3685 } 3073 3686 } 3074 3075 if (fNetworkLocked) 3076 RTSemFastMutexRelease(pNetwork->FastMutex2); 3077 } 3078 if (pTrunkIf) 3079 intnetR0TrunkIfOutUnlock(pTrunkIf); 3080 return rc; 3081 } 3082 3083 3084 /** 3085 * Activates or deactivates a interface. 3086 * 3087 * This is used to enable and disable the trunk connection on demans as well as 3088 * know when not to expect an interface to want to receive packets. 3089 * 3090 * @returns VBox status code. 3091 * @param pIf The interface. 3092 * @param fActive What to do. 3093 */ 3094 static int intnetR0IfSetActive(PINTNETIF pIf, bool fActive) 3095 { 3096 /* quick sanity check */ 3097 AssertPtrReturn(pIf, VERR_INVALID_POINTER); 3098 3099 /* 3100 * Hand it to the network since it might involve the trunk 3101 * and things are tricky there wrt to locking order. 3102 */ 3103 PINTNETNETWORK pNetwork = pIf->pNetwork; 3104 if (!pNetwork) 3105 return VERR_WRONG_ORDER; 3106 return intnetR0NetworkSetIfActive(pNetwork, pIf, fActive); 3687 } 3688 3689 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 3690 3691 /* 3692 * Tell the trunk if necessary. 3693 */ 3694 if (RT_SUCCESS(rcTrunkLock)) 3695 { 3696 if (fTellTrunk && pTrunk->pIfPort) 3697 pTrunk->pIfPort->pfnSetActive(pTrunk->pIfPort, fActive); 3698 3699 intnetR0TrunkIfOutUnlock(pTrunk); 3700 } 3701 3702 return VINF_SUCCESS; 3107 3703 } 3108 3704 … … 3133 3729 3134 3730 /* 3135 * Hand it to the network since it might involve the trunk 3136 * and things are tricky there wrt to locking order. 3137 */ 3731 * Hand it to the network since it might involve the trunk and things are 3732 * tricky there wrt to locking order. 3733 * 3734 * Note! We mark the interface busy so the network cannot be removed while 3735 * we're working on it - paranoia strikes again. 3736 */ 3737 intnetR0BusyIncIf(pIf); 3738 3138 3739 int rc; 3139 3740 PINTNETNETWORK pNetwork = pIf->pNetwork; … … 3143 3744 rc = VERR_WRONG_ORDER; 3144 3745 3746 intnetR0BusyDecIf(pIf); 3145 3747 intnetR0IfRelease(pIf, pSession); 3146 3748 return rc; … … 3189 3791 return VERR_INVALID_HANDLE; 3190 3792 } 3191 const INTNETIFHANDLE hIfSelf = pIf->hIf;3192 const RTSEMEVENT Event = pIf->Event;3193 if ( hIfSelf != hIf/* paranoia */3194 && Event != NIL_RTSEMEVENT)3793 const INTNETIFHANDLE hIfSelf = pIf->hIf; 3794 const RTSEMEVENT hRecvEvent = pIf->hRecvEvent; 3795 if ( hIfSelf != hIf /* paranoia */ 3796 && hRecvEvent != NIL_RTSEMEVENT) 3195 3797 { 3196 3798 Log(("INTNETR0IfWait: returns VERR_SEM_DESTROYED\n")); … … 3212 3814 */ 3213 3815 ASMAtomicIncU32(&pIf->cSleepers); 3214 int rc = RTSemEventWaitNoResume( Event, cMillies);3215 if (pIf-> Event ==Event)3816 int rc = RTSemEventWaitNoResume(hRecvEvent, cMillies); 3817 if (pIf->hRecvEvent == hRecvEvent) 3216 3818 { 3217 3819 ASMAtomicDecU32(&pIf->cSleepers); … … 3270 3872 ASMAtomicWriteU32(&pIf->hIf, INTNET_HANDLE_INVALID); 3271 3873 3272 3273 3874 /* 3274 3875 * Release the references to the interface object (handle + free lookup). … … 3276 3877 * will wake up too (he'll see hIf == invalid and return correctly). 3277 3878 */ 3278 RTSemEventSignal(pIf->Event); 3879 uint32_t i = pIf->cSleepers; 3880 while (i-- > 0) 3881 { 3882 RTSemEventSignal(pIf->hRecvEvent); 3883 RTThreadYield(); 3884 } 3885 RTSemEventSignal(pIf->hRecvEvent); 3279 3886 3280 3887 void *pvObj = pIf->pvObj; … … 3321 3928 * adding or removing interface while we're in here. For paranoid reasons 3322 3929 * we also mark the interface as destroyed here so any waiting threads can 3323 * take the appropriate actions(theoretical case).3930 * take evasive action (theoretical case). 3324 3931 */ 3325 3932 RTSemMutexRequest(pIntNet->hMtxCreateOpenDestroy, RT_INDEFINITE_WAIT); … … 3338 3945 3339 3946 /* 3340 * If we've got a network deactivate and unlink ourselves from it.3341 * Because of cleanup order we might be an orphan now.3947 * If we've got a network deactivate and detach ourselves from it. Because 3948 * of cleanup order we might have been orphaned by the network destructor. 3342 3949 */ 3343 3950 PINTNETNETWORK pNetwork = pIf->pNetwork; 3344 3951 if (pNetwork) 3345 3952 { 3346 intnetR0IfSetActive(pIf, false); 3347 3348 /* unlink */ 3349 if (pNetwork->pIfs == pIf) 3350 pNetwork->pIfs = pIf->pNext; 3351 else 3352 { 3353 PINTNETIF pPrev = pNetwork->pIfs; 3354 while (pPrev) 3953 /* set inactive. */ 3954 intnetR0NetworkSetIfActive(pNetwork, pIf, false /*fActive*/); 3955 3956 /* remove ourselves from the switch table. */ 3957 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 3958 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 3959 3960 uint32_t iIf = pNetwork->MacTab.cEntries; 3961 while (iIf-- > 0) 3962 if (pNetwork->MacTab.paEntries[iIf].pIf == pIf) 3355 3963 { 3356 if ( pPrev->pNext == pIf)3357 {3358 pPrev->pNext = pIf->pNext;3359 break;3360 }3361 pPrev = pPrev->pNext;3964 if (iIf + 1 < pNetwork->MacTab.cEntries) 3965 memmove(&pNetwork->MacTab.paEntries[iIf], 3966 &pNetwork->MacTab.paEntries[iIf + 1], 3967 (pNetwork->MacTab.cEntries - iIf - 1) * sizeof(pNetwork->MacTab.paEntries[0])); 3968 pNetwork->MacTab.cEntries--; 3969 break; 3362 3970 } 3363 Assert(pPrev); 3364 } 3365 pIf->pNext = NULL; 3971 3972 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 3973 3974 /* Wait for the interface to quiesce while we still can. */ 3975 intnetR0BusyWait(pNetwork, &pIf->cBusy); 3366 3976 3367 3977 /* Release our reference to the network. */ 3978 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 3979 pIf->pNetwork = NULL; 3980 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 3981 3368 3982 SUPR0ObjRelease(pNetwork->pvObj, pIf->pSession); 3369 pIf->pNetwork = NULL;3370 3983 } 3371 3984 … … 3378 3991 * that the interface is no longer valid. 3379 3992 */ 3380 if (pIf-> Event != NIL_RTSEMEVENT)3381 { 3382 RTSEMEVENT Event = pIf->Event;3383 unsigned cMaxWait= 0x1000;3993 if (pIf->hRecvEvent != NIL_RTSEMEVENT) 3994 { 3995 RTSEMEVENT hRecvEvent = pIf->hRecvEvent; 3996 unsigned cMaxWait = 0x1000; 3384 3997 while (pIf->cSleepers && cMaxWait-- > 0) 3385 3998 { 3386 RTSemEventSignal( Event);3999 RTSemEventSignal(hRecvEvent); 3387 4000 RTThreadYield(); 3388 4001 } … … 3394 4007 while (pIf->cSleepers && cMaxWait-- > 0) 3395 4008 { 3396 RTSemEventSignal( Event);4009 RTSemEventSignal(hRecvEvent); 3397 4010 RTThreadSleep(10); 3398 4011 } 3399 4012 } 3400 4013 3401 RTSemEventDestroy( Event);3402 pIf-> Event = NIL_RTSEMEVENT;4014 RTSemEventDestroy(hRecvEvent); 4015 pIf->hRecvEvent = NIL_RTSEMEVENT; 3403 4016 } 3404 4017 … … 3424 4037 3425 4038 /* 3426 * The interface. 3427 */ 4039 * Free remaining resources 4040 */ 4041 RTSpinlockDestroy(pIf->hRecvInSpinlock); 4042 pIf->hRecvInSpinlock = NIL_RTSPINLOCK; 4043 4044 RTMemFree(pIf->pDstTab); 4045 pIf->pDstTab = NULL; 4046 4047 for (unsigned i = 0; i < RT_ELEMENTS(pIf->aAddrCache); i++) 4048 if (pIf->aAddrCache[i].pbEntries) 4049 { 4050 RTMemFree(pIf->aAddrCache[i].pbEntries); 4051 pIf->aAddrCache[i].pbEntries = NULL; 4052 } 4053 3428 4054 pIf->pvObj = NULL; 3429 4055 RTMemFree(pIf); … … 3439 4065 * 3440 4066 * @returns VBox status code. 3441 * @param pNetwork The network. 4067 * @param pNetwork The network, referenced. The reference is consumed on 4068 * success. 3442 4069 * @param pSession The session handle. 3443 4070 * @param cbSend The size of the send buffer. … … 3458 4085 3459 4086 /* 3460 * Allocate and initialize the interface structure. 4087 * Make sure that all destination tables as well as the have space of 4088 */ 4089 int rc = intnetR0NetworkEnsureTabSpace(pNetwork); 4090 if (RT_FAILURE(rc)) 4091 return rc; 4092 4093 /* 4094 * Allocate the interface and initalize it. 3461 4095 */ 3462 4096 PINTNETIF pIf = (PINTNETIF)RTMemAllocZ(sizeof(*pIf)); 3463 4097 if (!pIf) 3464 4098 return VERR_NO_MEMORY; 3465 //pIf->pNext = NULL; 3466 memset(&pIf->Mac, 0xff, sizeof(pIf->Mac)); /* broadcast */ 3467 //pIf->fMacSet = false; 3468 //pIf->fPromiscuous = false; 3469 //pIf->fActive = false; 3470 //pIf->fDestroying = false; 3471 //pIf->pIntBuf = 0; 3472 //pIf->pIntBufR3 = NIL_RTR3PTR; 3473 //pIf->pIntBufDefault = 0; 4099 4100 memset(&pIf->MacAddr, 0xff, sizeof(pIf->MacAddr)); /* broadcast */ 4101 //pIf->fMacSet = false; 4102 //pIf->fPromiscuous = false; 4103 //pIf->fActive = false; 4104 //pIf->fDestroying = false; 4105 //pIf->cYields = 0; 4106 //pIf->pIntBuf = 0; 4107 //pIf->pIntBufR3 = NIL_RTR3PTR; 4108 //pIf->pIntBufDefault = 0; 3474 4109 //pIf->pIntBufDefaultR3 = NIL_RTR3PTR; 3475 //pIf->cYields = 0; 3476 pIf->Event = NIL_RTSEMEVENT; 3477 //pIf->cSleepers = 0; 3478 pIf->hIf = INTNET_HANDLE_INVALID; 3479 pIf->pNetwork = pNetwork; 3480 pIf->pSession = pSession; 3481 //pIf->pvObj = NULL; 3482 //pIf->aAddrCache[kIntNetAddrType_Invalid] = {0}; 3483 //pIf->aAddrCache[kIntNetAddrType_IPv4].pbEntries = NULL; 3484 //pIf->aAddrCache[kIntNetAddrType_IPv4].cEntries = 0; 4110 pIf->hRecvEvent = NIL_RTSEMEVENT; 4111 //pIf->cSleepers = 0; 4112 pIf->hIf = INTNET_HANDLE_INVALID; 4113 pIf->pNetwork = pNetwork; 4114 pIf->pSession = pSession; 4115 //pIf->pvObj = NULL; 4116 //pIf->aAddrCache[kIntNetAddrType_Invalid] = {0}; 4117 //pIf->aAddrCache[kIntNetAddrType_IPv4].pbEntries = NULL; 4118 //pIf->aAddrCache[kIntNetAddrType_IPv4].cEntries = 0; 3485 4119 //pIf->aAddrCache[kIntNetAddrType_IPv4].cEntriesAlloc = 0; 3486 pIf->aAddrCache[kIntNetAddrType_IPv4].cbAddress = intnetR0AddrSize(kIntNetAddrType_IPv4);3487 pIf->aAddrCache[kIntNetAddrType_IPv4].cbEntry = intnetR0AddrSize(kIntNetAddrType_IPv4);3488 //pIf->aAddrCache[kIntNetAddrType_IPv6].pbEntries = NULL;3489 //pIf->aAddrCache[kIntNetAddrType_IPv6].cEntries = 0;4120 pIf->aAddrCache[kIntNetAddrType_IPv4].cbAddress = intnetR0AddrSize(kIntNetAddrType_IPv4); 4121 pIf->aAddrCache[kIntNetAddrType_IPv4].cbEntry = intnetR0AddrSize(kIntNetAddrType_IPv4); 4122 //pIf->aAddrCache[kIntNetAddrType_IPv6].pbEntries = NULL; 4123 //pIf->aAddrCache[kIntNetAddrType_IPv6].cEntries = 0; 3490 4124 //pIf->aAddrCache[kIntNetAddrType_IPv6].cEntriesAlloc = 0; 3491 pIf->aAddrCache[kIntNetAddrType_IPv6].cbAddress = intnetR0AddrSize(kIntNetAddrType_IPv6); 3492 pIf->aAddrCache[kIntNetAddrType_IPv6].cbEntry = intnetR0AddrSize(kIntNetAddrType_IPv6); 3493 //pIf->aAddrCache[kIntNetAddrType_IPX].pbEntries = NULL; 3494 //pIf->aAddrCache[kIntNetAddrType_IPX].cEntries = 0; 3495 //pIf->aAddrCache[kIntNetAddrType_IPX].cEntriesAlloc = 0; 3496 pIf->aAddrCache[kIntNetAddrType_IPX].cbAddress = intnetR0AddrSize(kIntNetAddrType_IPX); 3497 pIf->aAddrCache[kIntNetAddrType_IPX].cbEntry = RT_ALIGN_32(intnetR0AddrSize(kIntNetAddrType_IPv4), 16); 3498 int rc = RTSemEventCreate((PRTSEMEVENT)&pIf->Event); 4125 pIf->aAddrCache[kIntNetAddrType_IPv6].cbAddress = intnetR0AddrSize(kIntNetAddrType_IPv6); 4126 pIf->aAddrCache[kIntNetAddrType_IPv6].cbEntry = intnetR0AddrSize(kIntNetAddrType_IPv6); 4127 //pIf->aAddrCache[kIntNetAddrType_IPX].pbEntries = NULL; 4128 //pIf->aAddrCache[kIntNetAddrType_IPX].cEntries = 0; 4129 //pIf->aAddrCache[kIntNetAddrType_IPX].cEntriesAlloc = 0; 4130 pIf->aAddrCache[kIntNetAddrType_IPX].cbAddress = intnetR0AddrSize(kIntNetAddrType_IPX); 4131 pIf->aAddrCache[kIntNetAddrType_IPX].cbEntry = RT_ALIGN_32(intnetR0AddrSize(kIntNetAddrType_IPX), 16); 4132 pIf->hRecvInSpinlock = NIL_RTSPINLOCK; 4133 pIf->cBusy = 0; 4134 //pIf->pDstTab = NULL; 4135 4136 rc = intnetR0AllocDstTab(pNetwork->MacTab.cEntriesAllocated, (PINTNETDSTTAB *)&pIf->pDstTab); 4137 if (RT_SUCCESS(rc)) 4138 rc = RTSemEventCreate((PRTSEMEVENT)&pIf->hRecvEvent); 4139 if (RT_SUCCESS(rc)) 4140 rc = RTSpinlockCreate(&pIf->hRecvInSpinlock); 3499 4141 if (RT_SUCCESS(rc)) 3500 4142 { … … 3516 4158 3517 4159 /* 3518 * Link the interface to the network.4160 * Register the interface with the session and create a handle for it. 3519 4161 */ 3520 rc = RTSemFastMutexRequest(pNetwork->FastMutex2); 3521 if (RT_SUCCESS(rc)) 4162 pIf->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK_INTERFACE, 4163 intnetR0IfDestruct, pIf, pNetwork->pIntNet); 4164 if (pIf->pvObj) 3522 4165 { 3523 pIf->pNext = pNetwork->pIfs; 3524 pNetwork->pIfs = pIf; 3525 RTSemFastMutexRelease(pNetwork->FastMutex2); 3526 3527 /* 3528 * Register the interface with the session, adding another 3529 * reference to the network to ease the cleanup duties of the caller. 3530 */ 3531 rc = SUPR0ObjAddRef(pNetwork->pvObj, pSession); 4166 rc = RTHandleTableAllocWithCtx(pNetwork->pIntNet->hHtIfs, pIf, pSession, (uint32_t *)&pIf->hIf); 3532 4167 if (RT_SUCCESS(rc)) 3533 4168 { 3534 pIf->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK_INTERFACE, intnetR0IfDestruct, pIf, pNetwork->pIntNet); 3535 if (pIf->pvObj) 3536 { 3537 rc = RTHandleTableAllocWithCtx(pNetwork->pIntNet->hHtIfs, pIf, pSession, (uint32_t *)&pIf->hIf); 3538 if (RT_SUCCESS(rc)) 3539 { 3540 *phIf = pIf->hIf; 3541 Log(("intnetR0NetworkCreateIf: returns VINF_SUCCESS *phIf=%RX32 cbSend=%u cbRecv=%u cbBuf=%u\n", 3542 *phIf, pIf->pIntBufDefault->cbSend, pIf->pIntBufDefault->cbRecv, pIf->pIntBufDefault->cbBuf)); 3543 return VINF_SUCCESS; 3544 } 3545 3546 SUPR0ObjRelease(pIf->pvObj, pSession); 3547 LogFlow(("intnetR0NetworkCreateIf: returns %Rrc\n", rc)); 3548 return rc; 3549 } 3550 3551 SUPR0ObjRelease(pNetwork->pvObj, pSession); 4169 /* 4170 * Finally add the interface to the network, consuming the 4171 * network reference of the caller. 4172 */ 4173 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 4174 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 4175 4176 uint32_t iIf = pNetwork->MacTab.cEntries; 4177 Assert(iIf + 1 <= pNetwork->MacTab.cEntriesAllocated); 4178 4179 pNetwork->MacTab.paEntries[iIf].MacAddr = pIf->MacAddr; 4180 pNetwork->MacTab.paEntries[iIf].fActive = false; 4181 pNetwork->MacTab.paEntries[iIf].fPromiscuous = false; 4182 pNetwork->MacTab.paEntries[iIf].pIf = pIf; 4183 4184 pNetwork->MacTab.cEntries = iIf + 1; 4185 pIf->pNetwork = pNetwork; 4186 4187 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 4188 4189 *phIf = pIf->hIf; 4190 Log(("intnetR0NetworkCreateIf: returns VINF_SUCCESS *phIf=%RX32 cbSend=%u cbRecv=%u cbBuf=%u\n", 4191 *phIf, pIf->pIntBufDefault->cbSend, pIf->pIntBufDefault->cbRecv, pIf->pIntBufDefault->cbBuf)); 4192 return VINF_SUCCESS; 3552 4193 } 3553 4194 3554 RTSemFastMutexDestroy(pNetwork->FastMutex2); 3555 pNetwork->FastMutex2 = NIL_RTSEMFASTMUTEX; 4195 SUPR0ObjRelease(pIf->pvObj, pSession); 4196 LogFlow(("intnetR0NetworkCreateIf: returns %Rrc\n", rc)); 4197 return rc; 3556 4198 } 3557 4199 4200 /* clean up */ 3558 4201 SUPR0MemFree(pIf->pSession, (RTHCUINTPTR)pIf->pIntBufDefault); 3559 4202 pIf->pIntBufDefault = NULL; 3560 4203 pIf->pIntBuf = NULL; 3561 4204 } 3562 3563 RTSemEventDestroy(pIf->Event); 3564 pIf->Event = NIL_RTSEMEVENT; 3565 } 4205 } 4206 4207 RTSpinlockDestroy(pIf->hRecvInSpinlock); 4208 pIf->hRecvInSpinlock = NIL_RTSPINLOCK; 4209 RTSemEventDestroy(pIf->hRecvEvent); 4210 pIf->hRecvEvent = NIL_RTSEMEVENT; 4211 RTMemFree(pIf->pDstTab); 3566 4212 RTMemFree(pIf); 3567 4213 LogFlow(("intnetR0NetworkCreateIf: returns %Rrc\n", rc)); … … 3607 4253 /* assert some sanity */ 3608 4254 AssertPtrReturn(pNetwork, INTNETSWDECISION_TRUNK); 3609 AssertReturn(pNetwork-> FastMutex2 != NIL_RTSEMFASTMUTEX, INTNETSWDECISION_TRUNK);4255 AssertReturn(pNetwork->hEvtBusyIf != NIL_RTSEMEVENT, INTNETSWDECISION_TRUNK); 3610 4256 AssertPtr(pvSrc); 3611 4257 AssertPtr(cbSrc >= 6); … … 3622 4268 { 3623 4269 PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort); 3624 PINTNETNETWORK pNetwork = pThis->pNetwork;3625 4270 3626 4271 /* assert some sanity */ 3627 AssertPtrReturn(pNetwork, false);3628 AssertReturn(pNetwork->FastMutex2 != NIL_RTSEMFASTMUTEX, false);3629 4272 AssertPtr(pSG); 3630 4273 Assert(fSrc); 3631 4274 3632 4275 /* 3633 * Lock the network and send the frame to it. 3634 */ 3635 int rc = RTSemFastMutexRequest(pNetwork->FastMutex2); 3636 AssertRCReturn(rc, false); 3637 3638 bool fRc; 3639 if (RT_LIKELY(pNetwork->cActiveIFs > 0)) 3640 fRc = intnetR0NetworkSend(pNetwork, NULL, fSrc, pSG, false /* fTrunkLocked */); 3641 else 3642 fRc = false; /* don't drop it */ 3643 3644 rc = RTSemFastMutexRelease(pNetwork->FastMutex2); 3645 AssertRC(rc); 3646 4276 * Mark the trunk as busy, make sure we've got a network and that there are 4277 * some active interfaces around. 4278 */ 4279 bool fRc = false /* don't drop it */; 4280 intnetR0BusyIncTrunk(pThis); 4281 PINTNETNETWORK pNetwork = pThis->pNetwork; 4282 if (RT_LIKELY( pNetwork 4283 && pNetwork->cActiveIFs > 0 )) 4284 { 4285 /* 4286 * Grab or allocate a destination table. 4287 */ 4288 bool const fIntCtx = RTThreadPreemptIsEnabled(NIL_RTTHREAD) || RTThreadIsInInterrupt(NIL_RTTHREAD); 4289 unsigned iDstTab = 0; 4290 PINTNETDSTTAB pDstTab = NULL; 4291 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 4292 RTSpinlockAcquireNoInts(pThis->hDstTabSpinlock, &Tmp); 4293 if (fIntCtx) 4294 { 4295 /* Interrupt or restricted context. */ 4296 iDstTab = RTMpCpuIdToSetIndex(RTMpCpuId()); 4297 iDstTab %= pThis->cIntDstTabs; 4298 pDstTab = pThis->apIntDstTabs[iDstTab]; 4299 if (RT_LIKELY(pDstTab)) 4300 pThis->apIntDstTabs[iDstTab] = NULL; 4301 else 4302 { 4303 iDstTab = pThis->cIntDstTabs; 4304 while (iDstTab-- > 0) 4305 { 4306 pDstTab = pThis->apIntDstTabs[iDstTab]; 4307 if (pDstTab) 4308 { 4309 pThis->apIntDstTabs[iDstTab] = NULL; 4310 break; 4311 } 4312 } 4313 } 4314 RTSpinlockReleaseNoInts(pThis->hDstTabSpinlock, &Tmp); 4315 Assert(!pDstTab || iDstTab < pThis->cIntDstTabs); 4316 } 4317 else 4318 { 4319 /* Task context, fallback is to allocate a table. */ 4320 AssertCompile(RT_ELEMENTS(pThis->apTaskDstTabs) == 2); /* for loop rollout */ 4321 pDstTab = pThis->apIntDstTabs[iDstTab = 0]; 4322 if (!pDstTab) 4323 pDstTab = pThis->apIntDstTabs[iDstTab = 1]; 4324 if (pDstTab) 4325 { 4326 pThis->apIntDstTabs[iDstTab] = NULL; 4327 RTSpinlockReleaseNoInts(pThis->hDstTabSpinlock, &Tmp); 4328 Assert(iDstTab < RT_ELEMENTS(pThis->apTaskDstTabs)); 4329 } 4330 else 4331 { 4332 RTSpinlockReleaseNoInts(pThis->hDstTabSpinlock, &Tmp); 4333 intnetR0AllocDstTab(pNetwork->MacTab.cEntriesAllocated, &pDstTab); 4334 iDstTab = 65535; 4335 } 4336 } 4337 if (RT_LIKELY(pDstTab)) 4338 { 4339 /* 4340 * Finally, get down to business of sending the frame. 4341 */ 4342 INTNETSWDECISION enmSwDecision = intnetR0NetworkSend(pNetwork, NULL, fSrc, pSG, pDstTab); 4343 Assert(enmSwDecision != INTNETSWDECISION_BAD_CONTEXT); 4344 if (enmSwDecision == INTNETSWDECISION_INTNET) 4345 fRc = true; /* drop it */ 4346 4347 /* 4348 * Free the destination table. 4349 */ 4350 if (iDstTab == 65535) 4351 RTMemFree(pDstTab); 4352 else 4353 { 4354 RTSpinlockAcquireNoInts(pThis->hDstTabSpinlock, &Tmp); 4355 if (fIntCtx && !pThis->apIntDstTabs[iDstTab]) 4356 pThis->apIntDstTabs[iDstTab] = pDstTab; 4357 else if (!fIntCtx && !pThis->apTaskDstTabs[iDstTab]) 4358 pThis->apTaskDstTabs[iDstTab] = pDstTab; 4359 else 4360 { 4361 /* this shouldn't happen! */ 4362 PINTNETDSTTAB *papDstTabs = fIntCtx ? &pThis->apIntDstTabs[0] : &pThis->apTaskDstTabs[0]; 4363 iDstTab = fIntCtx ? pThis->cIntDstTabs : RT_ELEMENTS(pThis->apTaskDstTabs); 4364 while (iDstTab-- > 0) 4365 if (!papDstTabs[iDstTab]) 4366 { 4367 papDstTabs[iDstTab] = pDstTab; 4368 break; 4369 } 4370 } 4371 RTSpinlockReleaseNoInts(pThis->hDstTabSpinlock, &Tmp); 4372 Assert(iDstTab < RT_MAX(RT_ELEMENTS(pThis->apTaskDstTabs), pThis->cIntDstTabs)); 4373 } 4374 } 4375 } 4376 4377 intnetR0BusyDecTrunk(pThis); 3647 4378 return fRc; 3648 4379 } … … 3657 4388 /* assert some sanity */ 3658 4389 AssertPtrReturnVoid(pNetwork); 3659 AssertReturnVoid(pNetwork-> FastMutex2 != NIL_RTSEMFASTMUTEX);4390 AssertReturnVoid(pNetwork->hEvtBusyIf != NIL_RTSEMEVENT); 3660 4391 AssertPtr(pSG); 3661 4392 Assert(pSG->cUsers > 0 && pSG->cUsers < 256); … … 3674 4405 /* assert some sanity */ 3675 4406 AssertPtrReturnVoid(pNetwork); 3676 AssertReturnVoid(pNetwork-> FastMutex2 != NIL_RTSEMFASTMUTEX);4407 AssertReturnVoid(pNetwork->hEvtBusyIf != NIL_RTSEMEVENT); 3677 4408 AssertPtr(pSG); 3678 4409 Assert(pSG->cUsers > 0); … … 3733 4464 { 3734 4465 AssertPtrReturn(pThis, false); 3735 int rc = RTSemFastMutexRequest(pThis->FastMutex );4466 int rc = RTSemFastMutexRequest(pThis->FastMutex3); 3736 4467 if (RT_SUCCESS(rc)) 3737 4468 { 3738 4469 if (RT_LIKELY(pThis->pIfPort)) 3739 4470 return true; 3740 RTSemFastMutexRelease(pThis->FastMutex );4471 RTSemFastMutexRelease(pThis->FastMutex3); 3741 4472 } 3742 4473 else … … 3755 4486 if (pThis) 3756 4487 { 3757 int rc = RTSemFastMutexRelease(pThis->FastMutex );4488 int rc = RTSemFastMutexRelease(pThis->FastMutex3); 3758 4489 AssertRC(rc); 3759 4490 } … … 3762 4493 3763 4494 /** 3764 * Activates the trunk interface.4495 * Deactivates the trunk interface. 3765 4496 * 3766 4497 * @param pThis The trunk. 3767 * @param fActive What to do with it.3768 4498 * 3769 4499 * @remarks Caller may only own the create/destroy lock. 3770 4500 */ 3771 static void intnetR0TrunkIf Activate(PINTNETTRUNKIF pThis, bool fActive)4501 static void intnetR0TrunkIfDeactivate(PINTNETTRUNKIF pThis) 3772 4502 { 3773 4503 if (intnetR0TrunkIfOutLock(pThis)) 3774 4504 { 3775 pThis->pIfPort->pfnSetActive(pThis->pIfPort, f Active);4505 pThis->pIfPort->pfnSetActive(pThis->pIfPort, false /*fActive*/); 3776 4506 intnetR0TrunkIfOutUnlock(pThis); 3777 4507 } … … 3843 4573 * Free up the resources. 3844 4574 */ 3845 RTSEMFASTMUTEX hFastMutex = pThis->FastMutex ;3846 pThis->FastMutex = NIL_RTSEMMUTEX;3847 pThis->pNetwork = NULL;4575 RTSEMFASTMUTEX hFastMutex = pThis->FastMutex3; 4576 pThis->FastMutex3 = NIL_RTSEMMUTEX; 4577 pThis->pNetwork = NULL; 3848 4578 RTSemFastMutexRelease(hFastMutex); 3849 4579 RTSemFastMutexDestroy(hFastMutex); 4580 RTSpinlockDestroy(pThis->hDstTabSpinlock); 4581 for (unsigned i = 0; i < RT_ELEMENTS(pThis->apTaskDstTabs); i++) 4582 { 4583 Assert(pThis->apTaskDstTabs[i]); 4584 RTMemFree(pThis->apTaskDstTabs[i]); 4585 pThis->apTaskDstTabs[i] = NULL; 4586 } 4587 for (unsigned i = 0; i < pThis->cIntDstTabs; i++) 4588 { 4589 Assert(pThis->apIntDstTabs[i]); 4590 RTMemFree(pThis->apIntDstTabs[i]); 4591 pThis->apIntDstTabs[i] = NULL; 4592 } 3850 4593 RTMemFree(pThis); 3851 4594 } … … 3895 4638 3896 4639 /* 3897 * Allocate the trunk interface. 3898 */ 3899 PINTNETTRUNKIF pTrunkIF = (PINTNETTRUNKIF)RTMemAllocZ(sizeof(*pTrunkIF)); 3900 if (!pTrunkIF) 4640 * Allocate the trunk interface and associated destination tables. 4641 * 4642 * We take a very optimistic view on the parallelism of the host 4643 * network stack and NIC driver. So, we allocate one table for each 4644 * possible CPU to deal with interrupt time requests and one for task 4645 * time calls. 4646 */ 4647 RTCPUID cCpus = RTMpGetCount(); Assert(cCpus > 0); 4648 PINTNETTRUNKIF pTrunk = (PINTNETTRUNKIF)RTMemAllocZ(RT_OFFSETOF(INTNETTRUNKIF, apIntDstTabs[cCpus])); 4649 if (!pTrunk) 3901 4650 return VERR_NO_MEMORY; 3902 pTrunkIF->SwitchPort.u32Version = INTNETTRUNKSWPORT_VERSION; 3903 pTrunkIF->SwitchPort.pfnPreRecv = intnetR0TrunkIfPortPreRecv; 3904 pTrunkIF->SwitchPort.pfnRecv = intnetR0TrunkIfPortRecv; 3905 pTrunkIF->SwitchPort.pfnSGRetain = intnetR0TrunkIfPortSGRetain; 3906 pTrunkIF->SwitchPort.pfnSGRelease = intnetR0TrunkIfPortSGRelease; 3907 pTrunkIF->SwitchPort.pfnSetSGPhys = intnetR0TrunkIfPortSetSGPhys; 3908 pTrunkIF->SwitchPort.pfnReportGsoCapabilities = intnetR0TrunkIfPortReportGsoCapabilities; 3909 pTrunkIF->SwitchPort.u32VersionEnd = INTNETTRUNKSWPORT_VERSION; 3910 //pTrunkIF->pIfPort = NULL; 3911 pTrunkIF->pNetwork = pNetwork; 3912 pTrunkIF->CachedMac.au8[0] = 0xfe; 3913 pTrunkIF->CachedMac.au8[1] = 0xff; 3914 pTrunkIF->CachedMac.au8[2] = 0xff; 3915 pTrunkIF->CachedMac.au8[3] = 0xff; 3916 pTrunkIF->CachedMac.au8[4] = 0xff; 3917 pTrunkIF->CachedMac.au8[5] = 0xff; 3918 //pTrunkIF->fPhysSG = false; 3919 //pTrunkIF->fWirePromiscuous = false; 3920 //pTrunkIF->fGroksGso = false; /** @todo query GSO support after connecting. */ 3921 int rc = RTSemFastMutexCreate(&pTrunkIF->FastMutex); 4651 4652 Assert(pNetwork->MacTab.cEntriesAllocated > 0); 4653 int rc = VINF_SUCCESS; 4654 pTrunk->cIntDstTabs = cCpus; 4655 for (unsigned i = 0; i < cCpus && RT_SUCCESS(rc); i++) 4656 rc = intnetR0AllocDstTab(pNetwork->MacTab.cEntriesAllocated, &pTrunk->apIntDstTabs[i]); 4657 for (unsigned i = 0; i < RT_ELEMENTS(pTrunk->apTaskDstTabs) && RT_SUCCESS(rc); i++) 4658 rc = intnetR0AllocDstTab(pNetwork->MacTab.cEntriesAllocated, &pTrunk->apTaskDstTabs[i]); 4659 3922 4660 if (RT_SUCCESS(rc)) 3923 4661 { 3924 #ifdef IN_RING0 /* (testcase is ring-3) */ 4662 pTrunk->SwitchPort.u32Version = INTNETTRUNKSWPORT_VERSION; 4663 pTrunk->SwitchPort.pfnPreRecv = intnetR0TrunkIfPortPreRecv; 4664 pTrunk->SwitchPort.pfnRecv = intnetR0TrunkIfPortRecv; 4665 pTrunk->SwitchPort.pfnSGRetain = intnetR0TrunkIfPortSGRetain; 4666 pTrunk->SwitchPort.pfnSGRelease = intnetR0TrunkIfPortSGRelease; 4667 pTrunk->SwitchPort.pfnSetSGPhys = intnetR0TrunkIfPortSetSGPhys; 4668 pTrunk->SwitchPort.pfnReportGsoCapabilities = intnetR0TrunkIfPortReportGsoCapabilities; 4669 pTrunk->SwitchPort.u32VersionEnd = INTNETTRUNKSWPORT_VERSION; 4670 pTrunk->FastMutex3 = NIL_RTSEMFASTMUTEX; 4671 //pTrunk->pIfPort = NULL; 4672 pTrunk->pNetwork = pNetwork; 4673 pTrunk->MacAddr.au8[0] = 0xff; 4674 pTrunk->MacAddr.au8[1] = 0xff; 4675 pTrunk->MacAddr.au8[2] = 0xff; 4676 pTrunk->MacAddr.au8[3] = 0xff; 4677 pTrunk->MacAddr.au8[4] = 0xff; 4678 pTrunk->MacAddr.au8[5] = 0xff; 4679 //pTrunk->fWireNoPreempt = false; 4680 //pTrunk->fHostNoPreempt = false; 4681 //pTrunk->fPhysSG = false; 4682 //pTrunk->cBusy = 0; 4683 //pTrunk->fWireGsoCapabilites = 0; 4684 //pTrunk->fHostGsoCapabilites = 0; 4685 //pTrunk->abGsoHdrs = {0}; 4686 pTrunk->hDstTabSpinlock = NIL_RTSPINLOCK; 4687 //pTrunk->apTaskDstTabs = above; 4688 //pTrunk->cIntDstTabs = above; 4689 //pTrunk->apIntDstTabs = above; 4690 3925 4691 /* 3926 * Query the factory we want, then use it create and connect the trunk.4692 * Create the locks (we've NIL'ed the members above to simplify cleanup). 3927 4693 */ 3928 PINTNETTRUNKFACTORY pTrunkFactory = NULL; 3929 rc = SUPR0ComponentQueryFactory(pSession, pszName, INTNETTRUNKFACTORY_UUID_STR, (void **)&pTrunkFactory); 4694 rc = RTSemFastMutexCreate(&pTrunk->FastMutex3); 4695 if (RT_SUCCESS(rc)) 4696 rc = RTSpinlockCreate(&pTrunk->hDstTabSpinlock); 3930 4697 if (RT_SUCCESS(rc)) 3931 4698 { 3932 rc = pTrunkFactory->pfnCreateAndConnect(pTrunkFactory, pNetwork->szTrunk, &pTrunkIF->SwitchPort, 3933 pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE 3934 ? INTNETTRUNKFACTORY_FLAG_NO_PROMISC : 0, 3935 &pTrunkIF->pIfPort); 3936 pTrunkFactory->pfnRelease(pTrunkFactory); 4699 #ifdef IN_RING0 /* (testcase is ring-3) */ 4700 /* 4701 * Query the factory we want, then use it create and connect the trunk. 4702 */ 4703 PINTNETTRUNKFACTORY pTrunkFactory = NULL; 4704 rc = SUPR0ComponentQueryFactory(pSession, pszName, INTNETTRUNKFACTORY_UUID_STR, (void **)&pTrunkFactory); 3937 4705 if (RT_SUCCESS(rc)) 3938 4706 { 3939 Assert(pTrunkIF->pIfPort); 3940 pNetwork->pTrunkIF = pTrunkIF; 3941 Log(("intnetR0NetworkCreateTrunkIf: VINF_SUCCESS - pszName=%s szTrunk=%s%s Network=%s\n", 3942 pszName, pNetwork->szTrunk, pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE ? " shared-mac" : "", pNetwork->szName)); 3943 return VINF_SUCCESS; 4707 rc = pTrunkFactory->pfnCreateAndConnect(pTrunkFactory, pNetwork->szTrunk, &pTrunk->SwitchPort, 4708 pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE 4709 ? INTNETTRUNKFACTORY_FLAG_NO_PROMISC : 0, 4710 &pTrunk->pIfPort); 4711 pTrunkFactory->pfnRelease(pTrunkFactory); 4712 if (RT_SUCCESS(rc)) 4713 { 4714 Assert(pTrunk->pIfPort); 4715 pNetwork->MacTab.pTrunk = pTrunk; 4716 4717 /* 4718 * Query the host info. 4719 * 4720 * Note! We don't need to lock the MacTab here since the 4721 * network is being created. 4722 */ 4723 /** @todo this should be reported by VBoxNet* instead of queried by us! */ 4724 intnetR0TrunkIfOutLock(pTrunk); 4725 4726 pTrunk->pIfPort->pfnGetMacAddress(pTrunk->pIfPort, &pTrunk->MacAddr); 4727 pNetwork->MacTab.HostMac = pTrunk->MacAddr; 4728 4729 pNetwork->MacTab.fHostPromiscuous = pTrunk->pIfPort->pfnIsPromiscuous(pTrunk->pIfPort); 4730 pNetwork->MacTab.fHostActive = true; 4731 4732 pNetwork->MacTab.fWirePromiscuous = false; /** @todo !!(fFlags & INTNET_OPEN_FLAGS_PROMISC_TRUNK_WIRE); */ 4733 pNetwork->MacTab.fWireActive = true; 4734 4735 intnetR0TrunkIfOutUnlock(pTrunk); 4736 4737 Log(("intnetR0NetworkCreateTrunkIf: VINF_SUCCESS - pszName=%s szTrunk=%s%s Network=%s\n", 4738 pszName, pNetwork->szTrunk, pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE ? " shared-mac" : "", pNetwork->szName)); 4739 return VINF_SUCCESS; 4740 } 3944 4741 } 4742 #else /* IN_RING3 */ 4743 rc = VERR_NOT_SUPPORTED; 4744 #endif /* IN_RING3 */ 3945 4745 } 3946 #endif /* IN_RING0 */ 3947 RTSemFastMutexDestroy(pTrunkIF->FastMutex); 3948 } 3949 RTMemFree(pTrunkIF); 4746 4747 /* bail out and clean up. */ 4748 RTSpinlockDestroy(pTrunk->hDstTabSpinlock); 4749 RTSemFastMutexDestroy(pTrunk->FastMutex3); 4750 } 4751 4752 for (unsigned i = 0; i < RT_ELEMENTS(pTrunk->apTaskDstTabs); i++) 4753 RTMemFree(pTrunk->apTaskDstTabs[i]); 4754 for (unsigned i = 0; i < pTrunk->cIntDstTabs; i++) 4755 RTMemFree(pTrunk->apIntDstTabs[i]); 4756 RTMemFree(pTrunk); 4757 3950 4758 LogFlow(("intnetR0NetworkCreateTrunkIf: %Rrc - pszName=%s szTrunk=%s Network=%s\n", 3951 4759 rc, pszName, pNetwork->szTrunk, pNetwork->szName)); … … 3966 4774 { 3967 4775 PINTNETNETWORK pNetwork = (PINTNETNETWORK)pvUser1; 3968 PINTNET pIntNet = (PINTNET)pvUser2;4776 PINTNET pIntNet = (PINTNET)pvUser2; 3969 4777 Log(("intnetR0NetworkDestruct: pvObj=%p pNetwork=%p pIntNet=%p %s\n", pvObj, pNetwork, pIntNet, pNetwork->szName)); 3970 4778 Assert(pNetwork->pIntNet == pIntNet); 3971 4779 3972 /* take the create/destroy sem. */4780 /* Take the big create/open/destroy sem. */ 3973 4781 RTSemMutexRequest(pIntNet->hMtxCreateOpenDestroy, RT_INDEFINITE_WAIT); 3974 4782 … … 3976 4784 * Deactivate the trunk connection first (if any). 3977 4785 */ 3978 if (pNetwork->pTrunkIF) 3979 intnetR0TrunkIfActivate(pNetwork->pTrunkIF, false /* fActive */); 4786 if (pNetwork->MacTab.pTrunk) 4787 intnetR0TrunkIfDeactivate(pNetwork->MacTab.pTrunk); 4788 4789 /* 4790 * Deactivate and orphan any remaining interfaces and wait for them to idle. 4791 * 4792 * Note! Normally there are no more interfaces at this point, however, when 4793 * supdrvCloseSession / supdrvCleanupSession release the objects the 4794 * order is undefined. So, it's quite possible that the network will 4795 * be dereference and destroyed before the interfaces. 4796 */ 4797 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 4798 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 4799 4800 uint32_t iIf = pNetwork->MacTab.cEntries; 4801 while (iIf-- > 0) 4802 { 4803 pNetwork->MacTab.paEntries[iIf].fActive = false; 4804 pNetwork->MacTab.paEntries[iIf].pIf->fActive = false; 4805 } 4806 4807 pNetwork->MacTab.fHostActive = false; 4808 pNetwork->MacTab.fWireActive = false; 4809 4810 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 4811 4812 /* Wait for all the interfaces to quiesce. (Interfaces cannot be 4813 removed / added since we're holding the big lock.) */ 4814 if (pNetwork->MacTab.pTrunk) 4815 intnetR0BusyWait(pNetwork, &pNetwork->MacTab.pTrunk->cBusy); 4816 4817 iIf = pNetwork->MacTab.cEntries; 4818 while (iIf-- > 0) 4819 intnetR0BusyWait(pNetwork, &pNetwork->MacTab.paEntries[iIf].pIf->cBusy); 4820 4821 /* Orphan the interfaces (not trunk). */ 4822 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 4823 while ((iIf = pNetwork->MacTab.cEntries) > 0) 4824 { 4825 PINTNETIF pIf = pNetwork->MacTab.paEntries[iIf - 1].pIf; 4826 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 4827 4828 intnetR0BusyWait(pNetwork, &pIf->cBusy); 4829 4830 RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp); 4831 if ( iIf == pNetwork->MacTab.cEntries /* paranoia */ 4832 && pIf->cBusy) 4833 { 4834 pIf->pNetwork = NULL; 4835 pNetwork->MacTab.cEntries--; 4836 } 4837 } 4838 4839 /* 4840 * Grab and zap the trunk pointer while we still own the spinlock, destroy 4841 * the trunk after we've left it. Note that this might take a while... 4842 */ 4843 PINTNETTRUNKIF pTrunk = pNetwork->MacTab.pTrunk; 4844 pNetwork->MacTab.pTrunk = NULL; 4845 4846 RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp); 4847 4848 if (pTrunk) 4849 intnetR0TrunkIfDestroy(pTrunk, pNetwork); 3980 4850 3981 4851 /* … … 3999 4869 4000 4870 /* 4001 * Because of the undefined order of the per session object dereferencing4002 * when closing a session, we have to handle the case where the network is4003 * destroyed before the interfaces.4004 * We deal with this simply by orphaning the interfaces.4005 */4006 RTSemFastMutexRequest(pNetwork->FastMutex2);4007 4008 PINTNETIF pCur = pNetwork->pIfs;4009 while (pCur)4010 {4011 PINTNETIF pNext = pCur->pNext;4012 pCur->pNext = NULL;4013 pCur->pNetwork = NULL;4014 pCur = pNext;4015 }4016 4017 /* Grab and zap the trunk pointer before leaving the mutex. */4018 PINTNETTRUNKIF pTrunkIF = pNetwork->pTrunkIF;4019 pNetwork->pTrunkIF = NULL;4020 4021 RTSemFastMutexRelease(pNetwork->FastMutex2);4022 4023 /*4024 * If there is a trunk, delete it.4025 * Note that this may tak a while if we're unlucky...4026 */4027 if (pTrunkIF)4028 intnetR0TrunkIfDestroy(pTrunkIF, pNetwork);4029 4030 /*4031 4871 * Free resources. 4032 4872 */ 4033 RTSemFastMutexDestroy(pNetwork->FastMutex2); 4034 pNetwork->FastMutex2 = NIL_RTSEMFASTMUTEX; 4873 RTSemEventDestroy(pNetwork->hEvtBusyIf); 4874 pNetwork->hEvtBusyIf = NIL_RTSEMEVENT; 4875 RTSpinlockDestroy(pNetwork->hAddrSpinlock); 4876 pNetwork->hAddrSpinlock = NIL_RTSPINLOCK; 4877 RTMemFree(pNetwork->MacTab.paEntries); 4878 pNetwork->MacTab.paEntries = NULL; 4035 4879 RTMemFree(pNetwork); 4036 4880 4037 /* release the create/destroy sem. (can be done before trunk destruction.)*/4881 /* Release the create/destroy sem. */ 4038 4882 RTSemMutexRelease(pIntNet->hMtxCreateOpenDestroy); 4039 4883 } … … 4174 5018 if (fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE) 4175 5019 cb += INTNETNETWORK_TMP_SIZE + 64; 4176 PINTNETNETWORK pNe w= (PINTNETNETWORK)RTMemAllocZ(cb);4177 if (!pNe w)5020 PINTNETNETWORK pNetwork = (PINTNETNETWORK)RTMemAllocZ(cb); 5021 if (!pNetwork) 4178 5022 return VERR_NO_MEMORY; 4179 int rc = RTSemFastMutexCreate(&pNew->FastMutex2); 5023 //pNetwork->pNext = NULL; 5024 //pNetwork->pIfs = NULL; 5025 pNetwork->hAddrSpinlock = NIL_RTSPINLOCK; 5026 pNetwork->MacTab.cEntries = 0; 5027 pNetwork->MacTab.cEntriesAllocated = INTNET_GROW_DSTTAB_SIZE; 5028 pNetwork->MacTab.paEntries = NULL; 5029 pNetwork->MacTab.fHostPromiscuous = false; 5030 pNetwork->MacTab.fHostActive = false; 5031 pNetwork->MacTab.fWirePromiscuous = false; 5032 pNetwork->MacTab.fWireActive = false; 5033 pNetwork->MacTab.pTrunk = NULL; 5034 pNetwork->hEvtBusyIf = NIL_RTSEMEVENT; 5035 pNetwork->pIntNet = pIntNet; 5036 //pNetwork->pvObj = NULL; 5037 if (fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE) 5038 pNetwork->pbTmp = RT_ALIGN_PT(pNetwork + 1, 64, uint8_t *); 5039 //else 5040 // pNetwork->pbTmp = NULL; 5041 pNetwork->fFlags = fFlags; 5042 //pNetwork->cActiveIFs = 0; 5043 size_t cchName = strlen(pszNetwork); 5044 pNetwork->cchName = (uint8_t)cchName; 5045 Assert(cchName && cchName < sizeof(pNetwork->szName)); /* caller's responsibility. */ 5046 memcpy(pNetwork->szName, pszNetwork, cchName); /* '\0' at courtesy of alloc. */ 5047 pNetwork->enmTrunkType = enmTrunkType; 5048 Assert(strlen(pszTrunk) < sizeof(pNetwork->szTrunk)); /* caller's responsibility. */ 5049 strcpy(pNetwork->szTrunk, pszTrunk); 5050 5051 /* 5052 * Create the semaphore, spinlock and allocate the interface table. 5053 */ 5054 int rc = RTSemEventCreate(&pNetwork->hEvtBusyIf); 4180 5055 if (RT_SUCCESS(rc)) 4181 { 4182 //pNew->pIfs = NULL; 4183 pNew->pIntNet = pIntNet; 4184 //pNew->cActiveIFs = 0; 4185 pNew->fFlags = fFlags; 4186 size_t cchName = strlen(pszNetwork); 4187 pNew->cchName = (uint8_t)cchName; 4188 Assert(cchName && cchName < sizeof(pNew->szName)); /* caller's responsibility. */ 4189 memcpy(pNew->szName, pszNetwork, cchName); /* '\0' by alloc. */ 4190 pNew->enmTrunkType = enmTrunkType; 4191 Assert(strlen(pszTrunk) < sizeof(pNew->szTrunk)); /* caller's responsibility. */ 4192 strcpy(pNew->szTrunk, pszTrunk); 4193 if (fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE) 4194 pNew->pbTmp = RT_ALIGN_PT(pNew + 1, 64, uint8_t *); 4195 //else 4196 // pNew->pbTmp = NULL; 4197 5056 rc = RTSpinlockCreate(&pNetwork->hAddrSpinlock); 5057 if (RT_SUCCESS(rc)) 5058 { 5059 pNetwork->MacTab.paEntries = (PINTNETMACTABENTRY)RTMemAlloc(sizeof(INTNETMACTABENTRY) * pNetwork->MacTab.cEntriesAllocated); 5060 if (!pNetwork->MacTab.paEntries) 5061 rc = VERR_NO_MEMORY; 5062 } 5063 if (RT_SUCCESS(rc)) 5064 { 4198 5065 /* 4199 5066 * Register the object in the current session and link it into the network list. 4200 5067 */ 4201 pNe w->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK, intnetR0NetworkDestruct, pNew, pIntNet);4202 if (pNe w->pvObj)5068 pNetwork->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK, intnetR0NetworkDestruct, pNetwork, pIntNet); 5069 if (pNetwork->pvObj) 4203 5070 { 4204 pNe w->pNext = pIntNet->pNetworks;4205 pIntNet->pNetworks = pNe w;5071 pNetwork->pNext = pIntNet->pNetworks; 5072 pIntNet->pNetworks = pNetwork; 4206 5073 4207 5074 /* … … 4211 5078 * does no such checks. 4212 5079 */ 4213 rc = SUPR0ObjVerifyAccess(pNe w->pvObj, pSession, pNew->szName);5080 rc = SUPR0ObjVerifyAccess(pNetwork->pvObj, pSession, pNetwork->szName); 4214 5081 if (RT_SUCCESS(rc)) 4215 5082 { … … 4217 5084 * Connect the trunk. 4218 5085 */ 4219 rc = intnetR0NetworkCreateTrunkIf(pNe w, pSession);5086 rc = intnetR0NetworkCreateTrunkIf(pNetwork, pSession); 4220 5087 if (RT_SUCCESS(rc)) 4221 5088 { 4222 *ppNetwork = pNe w;4223 LogFlow(("intnetR0CreateNetwork: returns VINF_SUCCESS *ppNetwork=%p\n", pNe w));5089 *ppNetwork = pNetwork; 5090 LogFlow(("intnetR0CreateNetwork: returns VINF_SUCCESS *ppNetwork=%p\n", pNetwork)); 4224 5091 return VINF_SUCCESS; 4225 5092 } 4226 5093 } 4227 5094 4228 SUPR0ObjRelease(pNe w->pvObj, pSession);5095 SUPR0ObjRelease(pNetwork->pvObj, pSession); 4229 5096 LogFlow(("intnetR0CreateNetwork: returns %Rrc\n", rc)); 4230 5097 return rc; 4231 5098 } 5099 5100 /* cleanup */ 4232 5101 rc = VERR_NO_MEMORY; 4233 4234 RTSemFastMutexDestroy(pNew->FastMutex2); 4235 pNew->FastMutex2 = NIL_RTSEMFASTMUTEX; 4236 } 4237 RTMemFree(pNew); 5102 } 5103 5104 RTSemEventDestroy(pNetwork->hEvtBusyIf); 5105 pNetwork->hEvtBusyIf = NIL_RTSEMEVENT; 5106 RTSpinlockDestroy(pNetwork->hAddrSpinlock); 5107 pNetwork->hAddrSpinlock = NIL_RTSPINLOCK; 5108 RTMemFree(pNetwork->MacTab.paEntries); 5109 pNetwork->MacTab.paEntries = NULL; 5110 RTMemFree(pNetwork); 5111 4238 5112 LogFlow(("intnetR0CreateNetwork: returns %Rrc\n", rc)); 4239 5113 return rc; … … 4324 5198 if (RT_SUCCESS(rc)) 4325 5199 rc = VINF_ALREADY_INITIALIZED; 4326 SUPR0ObjRelease(pNetwork->pvObj, pSession); 5200 else 5201 SUPR0ObjRelease(pNetwork->pvObj, pSession); 4327 5202 } 4328 5203 else if (rc == VERR_NOT_FOUND) … … 4332 5207 { 4333 5208 rc = intnetR0NetworkCreateIf(pNetwork, pSession, cbSend, cbRecv, phIf); 4334 SUPR0ObjRelease(pNetwork->pvObj, pSession); 5209 if (RT_FAILURE(rc)) 5210 SUPR0ObjRelease(pNetwork->pvObj, pSession); 4335 5211 } 4336 5212 } -
trunk/src/VBox/Devices/Network/testcase/tstIntNetR0.cpp
r28314 r28623 41 41 #include <VBox/sup.h> 42 42 #include <VBox/err.h> 43 #include <iprt/asm.h> 44 #include <iprt/getopt.h> 45 #include <iprt/initterm.h> 46 #include <iprt/mem.h> 47 #include <iprt/mp.h> 43 48 #include <iprt/stream.h> 44 #include <iprt/alloc.h>45 #include <iprt/initterm.h>46 49 #include <iprt/thread.h> 47 50 #include <iprt/time.h> 48 #include <iprt/asm.h> 49 #include <iprt/getopt.h> 51 #include <iprt/test.h> 50 52 51 53 … … 98 100 * Global Variables * 99 101 *******************************************************************************/ 100 /** The error count. */ 101 unsigned g_cErrors = 0; 102 102 /** The test handle.*/ 103 static RTTEST g_hTest = NIL_RTTEST; 104 /** The size (in bytes) of the large transfer tests. */ 105 static uint32_t g_cbTransfer = _1M * 384; 103 106 /** Fake session handle. */ 104 const PSUPDRVSESSION g_pSession = (PSUPDRVSESSION)0xdeadface; 105 106 /** Testframe 0 */ 107 struct TESTFRAME 108 { 109 uint16_t au16[7]; 110 } g_TestFrame0 = { { /* dst:*/ 0xffff, 0xffff, 0xffff, /*src:*/0x8086, 0, 0, 0x0800 } }, 111 g_TestFrame1 = { { /* dst:*/ 0, 0, 0, /*src:*/0x8086, 0, 1, 0x0800 } }; 107 const PSUPDRVSESSION g_pSession = (PSUPDRVSESSION)0xdeadface; 112 108 113 109 114 110 INTNETR3DECL(void *) SUPR0ObjRegister(PSUPDRVSESSION pSession, SUPDRVOBJTYPE enmType, PFNSUPDRVDESTRUCTOR pfnDestructor, void *pvUser1, void *pvUser2) 115 111 { 116 if (pSession != g_pSession) 117 { 118 RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__); 119 g_cErrors++; 120 return NULL; 121 } 122 POBJREF pRef = (POBJREF)RTMemAlloc(sizeof(OBJREF)); 112 RTTEST_CHECK_RET(g_hTest, pSession == g_pSession, NULL); 113 POBJREF pRef = (POBJREF)RTTestGuardedAllocTail(g_hTest, sizeof(OBJREF)); 123 114 if (!pRef) 124 115 return NULL; … … 132 123 INTNETR3DECL(int) SUPR0ObjAddRefEx(void *pvObj, PSUPDRVSESSION pSession, bool fNoBlocking) 133 124 { 134 if (pSession != g_pSession) 135 { 136 RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__); 137 g_cErrors++; 138 return VERR_INVALID_PARAMETER; 139 } 125 RTTEST_CHECK_RET(g_hTest, pSession == g_pSession, VERR_INVALID_PARAMETER); 140 126 POBJREF pRef = (POBJREF)pvObj; 141 127 ASMAtomicIncU32(&pRef->cRefs); … … 150 136 INTNETR3DECL(int) SUPR0ObjRelease(void *pvObj, PSUPDRVSESSION pSession) 151 137 { 152 if (pSession != g_pSession) 153 { 154 RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__); 155 g_cErrors++; 156 return VERR_INVALID_PARAMETER; 157 } 138 RTTEST_CHECK_RET(g_hTest, pSession == g_pSession, VERR_INVALID_PARAMETER); 158 139 POBJREF pRef = (POBJREF)pvObj; 159 140 if (!ASMAtomicDecU32(&pRef->cRefs)) 160 141 { 161 142 pRef->pfnDestructor(pRef, pRef->pvUser1, pRef->pvUser2); 162 RT MemFree(pRef);143 RTTestGuardedFree(g_hTest, pRef); 163 144 return VINF_OBJECT_DESTROYED; 164 145 } … … 168 149 INTNETR3DECL(int) SUPR0ObjVerifyAccess(void *pvObj, PSUPDRVSESSION pSession, const char *pszObjName) 169 150 { 170 if (pSession != g_pSession) 171 { 172 RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__); 173 g_cErrors++; 174 return VERR_INVALID_PARAMETER; 175 } 151 RTTEST_CHECK_RET(g_hTest, pSession == g_pSession, VERR_INVALID_PARAMETER); 176 152 return VINF_SUCCESS; 177 153 } … … 179 155 INTNETR3DECL(int) SUPR0MemAlloc(PSUPDRVSESSION pSession, uint32_t cb, PRTR0PTR ppvR0, PRTR3PTR ppvR3) 180 156 { 181 if (pSession != g_pSession) 182 { 183 RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__); 184 g_cErrors++; 185 return VERR_INVALID_PARAMETER; 186 } 187 void *pv = RTMemAlloc(cb); 157 RTTEST_CHECK_RET(g_hTest, pSession == g_pSession, VERR_INVALID_PARAMETER); 158 void *pv = RTTestGuardedAllocTail(g_hTest, cb); 188 159 if (!pv) 189 160 return VERR_NO_MEMORY; … … 196 167 INTNETR3DECL(int) SUPR0MemFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr) 197 168 { 198 if (pSession != g_pSession) 199 { 200 RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__); 201 g_cErrors++; 202 return VERR_INVALID_PARAMETER; 203 } 204 RTMemFree((void *)uPtr); 169 RTTEST_CHECK_RET(g_hTest, pSession == g_pSession, VERR_INVALID_PARAMETER); 170 RTTestGuardedFree(g_hTest, (void *)uPtr); 205 171 return VINF_SUCCESS; 206 172 } 207 173 174 /* Fake non-existing ring-0 APIs. */ 175 #define RTThreadIsInInterrupt(hThread) false 176 #define RTThreadPreemptIsEnabled(hThread) true 177 #define RTMpCpuId() 0 178 179 /* No CLI/POPF, please. */ 180 #define RTSpinlockAcquireNoInts RTSpinlockAcquire 181 #define RTSpinlockReleaseNoInts RTSpinlockRelease 208 182 209 183 … … 230 204 typedef struct MYARGS 231 205 { 232 PINTNET pIntNet;233 PINTNETBUF pBuf;234 INTNETIFHANDLE hIf;235 RTMAC Mac;236 uint64_t u64Start;237 uint64_t u64End;206 PINTNET pIntNet; 207 PINTNETBUF pBuf; 208 INTNETIFHANDLE hIf; 209 RTMAC Mac; 210 uint64_t u64Start; 211 uint64_t u64End; 238 212 } MYARGS, *PMYARGS; 239 213 240 214 241 #define TEST_TRANSFER_SIZE (_1M*384) 215 /** 216 * Frame header used when testing. 217 */ 218 #pragma pack(1) 219 typedef struct MYFRAMEHDR 220 { 221 RTMAC SrcMac; 222 RTMAC DstMac; 223 uint32_t iFrame; 224 uint32_t auEos[3]; 225 } MYFRAMEHDR; 226 #pragma pack() 242 227 243 228 /** … … 248 233 { 249 234 PMYARGS pArgs = (PMYARGS)pvArg; 250 251 /* 252 * Send 64 MB of data. 253 */ 254 uint8_t abBuf[4096] = {0}; 255 PRTMAC pMacSrc = (PRTMAC)&abBuf[0]; 256 PRTMAC pMacDst = pMacSrc + 1; 257 *pMacSrc = pArgs->Mac; 258 *pMacDst = pArgs->Mac; 259 pMacDst->au16[2] = pArgs->Mac.au16[2] ? 0 : 1; 260 unsigned *puFrame = (unsigned *)(pMacDst + 1); 261 unsigned iFrame = 0; 262 uint32_t cbSent = 0; 263 uint32_t cSend = 0; 235 int rc; 236 237 /* 238 * Send g_cbTransfer of data. 239 */ 240 uint8_t abBuf[4096] = {0}; 241 MYFRAMEHDR *pHdr = (MYFRAMEHDR *)&abBuf[0]; 242 uint32_t iFrame = 0; 243 uint32_t cbSent = 0; 244 uint32_t cSend = 0; 245 246 pHdr->SrcMac = pArgs->Mac; 247 pHdr->DstMac = pArgs->Mac; 248 pHdr->DstMac.au16[2] = (pArgs->Mac.au16[2] + 1) % 2; 249 264 250 pArgs->u64Start = RTTimeNanoTS(); 265 for (; cbSent < TEST_TRANSFER_SIZE; iFrame++)266 { 267 const unsigned cb = iFrame % 1519 + 12 + sizeof(unsigned);268 *puFrame = iFrame;251 for (; cbSent < g_cbTransfer; iFrame++) 252 { 253 const unsigned cb = iFrame % 1519 + sizeof(RTMAC) * 2 + sizeof(unsigned); 254 pHdr->iFrame = iFrame; 269 255 270 256 INTNETSG Sg; 271 257 INTNETSgInitTemp(&Sg, abBuf, cb); 272 int rc = intnetR0RingWriteFrame(&pArgs->pBuf->Send, &Sg, NULL);258 RTTEST_CHECK_RC_OK(g_hTest, rc = intnetR0RingWriteFrame(&pArgs->pBuf->Send, &Sg, NULL)); 273 259 if (RT_SUCCESS(rc)) 274 rc = INTNETR0IfSend(pArgs->pIntNet, pArgs->hIf, g_pSession); 275 if (RT_FAILURE(rc)) 276 { 277 g_cErrors++; 278 RTPrintf("tstIntNetR0: Failed sending %d bytes, rc=%Rrc (%d)\n", cb, rc, INTNETRingGetWritable(&pArgs->pBuf->Send)); 279 } 260 RTTEST_CHECK_RC_OK(g_hTest, rc = INTNETR0IfSend(pArgs->pIntNet, pArgs->hIf, g_pSession)); 280 261 cbSent += cb; 281 262 } … … 284 265 * Termination frames. 285 266 */ 286 p uFrame[0]= 0xffffdead;287 p uFrame[1] = 0xffffdead;288 p uFrame[2] = 0xffffdead;289 p uFrame[3] = 0xffffdead;267 pHdr->iFrame = 0xffffdead; 268 pHdr->auEos[0] = 0xffffdead; 269 pHdr->auEos[1] = 0xffffdead; 270 pHdr->auEos[2] = 0xffffdead; 290 271 for (unsigned c = 0; c < 20; c++) 291 272 { 292 int rc = tstIntNetSendBuf(pArgs->pIntNet, &pArgs->pBuf->Send, pArgs->hIf, g_pSession, 293 abBuf, sizeof(RTMAC) * 2 + sizeof(unsigned) * 4); 294 if (RT_FAILURE(rc)) 295 { 296 g_cErrors++; 297 RTPrintf("tstIntNetR0: send failed, rc=%Rrc\n", rc); 298 } 273 RTTEST_CHECK_RC_OK(g_hTest, rc = tstIntNetSendBuf(pArgs->pIntNet, &pArgs->pBuf->Send, pArgs->hIf, g_pSession, 274 abBuf, sizeof(RTMAC) * 2 + sizeof(unsigned) * 4)); 299 275 RTThreadSleep(1); 300 276 } 301 277 302 RTPrintf("tstIntNetR0: sender thread %.6Rhxs terminating.\n" 303 "tstIntNetR0: iFrame=%u cb=%'u\n", 304 &pArgs->Mac, iFrame, cbSent); 278 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, 279 "sender thread %.6Rhxs terminating.\n" 280 "iFrame=%u cb=%'u\n", 281 &pArgs->Mac, iFrame, cbSent); 305 282 return 0; 306 283 } … … 322 299 for (;;) 323 300 { 301 /* 302 * Read data. 303 */ 304 while (INTNETRingHasMoreToRead(&pArgs->pBuf->Recv)) 305 { 306 uint8_t abBuf[16384]; 307 MYFRAMEHDR *pHdr = (MYFRAMEHDR *)&abBuf[0]; 308 uint32_t cb = INTNETRingReadAndSkipFrame(&pArgs->pBuf->Recv, abBuf); 309 310 /* check for termination frame. */ 311 if ( pHdr->iFrame == 0xffffdead 312 && pHdr->auEos[0] == 0xffffdead 313 && pHdr->auEos[1] == 0xffffdead 314 && pHdr->auEos[2] == 0xffffdead) 315 { 316 pArgs->u64End = RTTimeNanoTS(); 317 RTThreadSleep(10); 318 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, 319 "receiver thread %.6Rhxs terminating.\n" 320 " iFrame=%u cb=%'u c=%'u %'uKB/s %'ufps cLost=%'u \n", 321 &pArgs->Mac, iFrame, cbReceived, iFrame - cLostFrames, 322 (unsigned)(cbReceived * 1000000000.0 / 1024 / (pArgs->u64End - pArgs->u64Start)), 323 (unsigned)((iFrame - cLostFrames) * 1000000000.0 / (pArgs->u64End - pArgs->u64Start)), 324 cLostFrames); 325 return VINF_SUCCESS; 326 } 327 328 /* validate frame header */ 329 if ( pHdr->DstMac.au16[0] != pArgs->Mac.au16[0] 330 || pHdr->DstMac.au16[1] != pArgs->Mac.au16[1] 331 || pHdr->DstMac.au16[2] != pArgs->Mac.au16[2] 332 || pHdr->SrcMac.au16[0] != pArgs->Mac.au16[0] 333 || pHdr->SrcMac.au16[1] != pArgs->Mac.au16[1] 334 || pHdr->SrcMac.au16[2] != (pArgs->Mac.au16[2] + 1) % 2) 335 { 336 RTTestFailed(g_hTest, "receiver thread %.6Rhxs received frame header: %.16Rhxs\n", &pArgs->Mac, abBuf); 337 } 338 339 /* frame stuff and stats. */ 340 int32_t off = pHdr->iFrame - (iFrame + 1); 341 if (off) 342 { 343 if (off > 0) 344 { 345 #ifndef IGNORE_LOST_FRAMES 346 RTTestFailed(g_hTest, "receiver thread %.6Rhxs: iFrame=%#x *puFrame=%#x off=%d\n", 347 &pArgs->Mac, iFrame, pHdr->iFrame, off); 348 #endif 349 cLostFrames += off; 350 } 351 else 352 { 353 cLostFrames++; 354 RTTestFailed(g_hTest, "receiver thread %.6Rhxs: iFrame=%#x *puFrame=%#x off=%d\n", 355 &pArgs->Mac, iFrame, pHdr->iFrame, off); 356 } 357 } 358 iFrame = pHdr->iFrame; 359 cbReceived += cb; 360 } 361 324 362 /* 325 363 * Wait for data. … … 332 370 break; 333 371 case VERR_SEM_DESTROYED: 334 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs terminating. iFrame=%u cb=%'u c=%'u cLost=%'u\n", 335 &pArgs->Mac, iFrame, cbReceived, iFrame - cLostFrames, cLostFrames); 372 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, 373 "receiver thread %.6Rhxs terminating. iFrame=%u cb=%'u c=%'u cLost=%'u\n", 374 &pArgs->Mac, iFrame, cbReceived, iFrame - cLostFrames, cLostFrames); 336 375 return VINF_SUCCESS; 337 376 338 377 default: 339 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs got odd return value %Rrc! iFrame=%u cb=%'u c=%'u cLost=%'u\n", 340 &pArgs->Mac, rc, iFrame, cbReceived, iFrame - cLostFrames, cLostFrames); 341 g_cErrors++; 378 RTTestFailed(g_hTest, "receiver thread %.6Rhxs got odd return value %Rrc! iFrame=%u cb=%'u c=%'u cLost=%'u\n", 379 &pArgs->Mac, rc, iFrame, cbReceived, iFrame - cLostFrames, cLostFrames); 342 380 return rc; 343 381 } 344 382 383 } 384 } 385 386 387 /** 388 * Test state. 389 */ 390 typedef struct TSTSTATE 391 { 392 PINTNET pIntNet; 393 394 PINTNETBUF pBuf0; 395 INTNETIFHANDLE hIf0; 396 397 PINTNETBUF pBuf1; 398 INTNETIFHANDLE hIf1; 399 } TSTSTATE; 400 typedef TSTSTATE *PTSTSTATE; 401 402 403 /** 404 * Open two internal network interfaces. 405 * 406 * @returns IPRT status of the first failure. 407 * @param pThis The test instance. 408 */ 409 static int tstOpenInterfaces(PTSTSTATE pThis, const char *pszNetwork, uint32_t cbSend, uint32_t cbRecv) 410 { 411 pThis->hIf0 = INTNET_HANDLE_INVALID; 412 RTTESTI_CHECK_RC_OK_RET(INTNETR0Open(pThis->pIntNet, g_pSession, pszNetwork, kIntNetTrunkType_None, "", 413 0/*fFlags*/, cbSend, cbRecv, &pThis->hIf0), rcCheck); 414 RTTESTI_CHECK_RET(pThis->hIf0 != INTNET_HANDLE_INVALID, VERR_INTERNAL_ERROR); 415 RTTESTI_CHECK_RC_RET(INTNETR0IfGetRing0Buffer(pThis->pIntNet, pThis->hIf0, g_pSession, &pThis->pBuf0), VINF_SUCCESS, rcCheck); 416 RTTESTI_CHECK_RET(pThis->pBuf0, VERR_INTERNAL_ERROR); 417 418 419 pThis->hIf1 = INTNET_HANDLE_INVALID; 420 RTTESTI_CHECK_RC_OK_RET(INTNETR0Open(pThis->pIntNet, g_pSession, pszNetwork, kIntNetTrunkType_None, "", 421 0/*fFlags*/, cbSend, cbRecv, &pThis->hIf1), rcCheck); 422 RTTESTI_CHECK_RET(pThis->hIf1 != INTNET_HANDLE_INVALID, VERR_INTERNAL_ERROR); 423 RTTESTI_CHECK_RC_RET(INTNETR0IfGetRing0Buffer(pThis->pIntNet, pThis->hIf1, g_pSession, &pThis->pBuf1), VINF_SUCCESS, rcCheck); 424 RTTESTI_CHECK_RET(pThis->pBuf1, VERR_INTERNAL_ERROR); 425 426 return VINF_SUCCESS; 427 } 428 429 /** 430 * Close the interfaces. 431 * 432 * @param pThis The test instance. 433 */ 434 static void tstCloseInterfaces(PTSTSTATE pThis) 435 { 436 int rc; 437 RTTESTI_CHECK_RC_OK(rc = INTNETR0IfClose(pThis->pIntNet, pThis->hIf0, g_pSession)); 438 if (RT_SUCCESS(rc)) 439 { 440 pThis->hIf0 = INTNET_HANDLE_INVALID; 441 pThis->pBuf0 = NULL; 442 } 443 444 RTTESTI_CHECK_RC_OK(rc = INTNETR0IfClose(pThis->pIntNet, pThis->hIf1, g_pSession)); 445 if (RT_SUCCESS(rc)) 446 { 447 pThis->hIf1 = INTNET_HANDLE_INVALID; 448 pThis->pBuf1 = NULL; 449 } 450 451 /* The network should be dead now. */ 452 RTTESTI_CHECK(pThis->pIntNet->pNetworks == NULL); 453 } 454 455 /** 456 * Do the bi-directional transfer test. 457 */ 458 static void tstBidirectionalTransfer(PTSTSTATE pThis) 459 { 460 MYARGS Args0; 461 RT_ZERO(Args0); 462 Args0.hIf = pThis->hIf0; 463 Args0.pBuf = pThis->pBuf0; 464 Args0.pIntNet = pThis->pIntNet; 465 Args0.Mac.au16[0] = 0x8086; 466 Args0.Mac.au16[1] = 0; 467 Args0.Mac.au16[2] = 0; 468 469 MYARGS Args1; 470 RT_ZERO(Args1); 471 Args1.hIf = pThis->hIf1; 472 Args1.pBuf = pThis->pBuf1; 473 Args1.pIntNet = pThis->pIntNet; 474 Args1.Mac.au16[0] = 0x8086; 475 Args1.Mac.au16[1] = 0; 476 Args1.Mac.au16[2] = 1; 477 478 RTTHREAD ThreadRecv0 = NIL_RTTHREAD; 479 RTTHREAD ThreadRecv1 = NIL_RTTHREAD; 480 RTTHREAD ThreadSend0 = NIL_RTTHREAD; 481 RTTHREAD ThreadSend1 = NIL_RTTHREAD; 482 RTTESTI_CHECK_RC_OK_RETV(RTThreadCreate(&ThreadRecv0, ReceiveThread, &Args0, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "RECV0")); 483 RTTESTI_CHECK_RC_OK_RETV(RTThreadCreate(&ThreadRecv1, ReceiveThread, &Args1, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "RECV1")); 484 RTTESTI_CHECK_RC_OK_RETV(RTThreadCreate(&ThreadSend0, SendThread, &Args0, 0, RTTHREADTYPE_EMULATION, RTTHREADFLAGS_WAITABLE, "SEND0")); 485 RTTESTI_CHECK_RC_OK_RETV(RTThreadCreate(&ThreadSend1, SendThread, &Args1, 0, RTTHREADTYPE_EMULATION, RTTHREADFLAGS_WAITABLE, "SEND1")); 486 487 int rc2 = VINF_SUCCESS; 488 int rc; 489 RTTESTI_CHECK_RC_OK(rc = RTThreadWait(ThreadSend0, 5*60*1000, &rc2)); 490 if (RT_SUCCESS(rc)) 491 { 492 RTTESTI_CHECK_RC_OK(rc2); 493 ThreadSend0 = NIL_RTTHREAD; 494 RTTESTI_CHECK_RC_OK(rc = RTThreadWait(ThreadSend1, 5*60*1000, RT_SUCCESS(rc2) ? &rc2 : NULL)); 495 if (RT_SUCCESS(rc)) 496 { 497 ThreadSend1 = NIL_RTTHREAD; 498 RTTESTI_CHECK_RC_OK(rc2); 499 } 500 } 501 if (RTTestErrorCount(g_hTest) == 0) 502 { 345 503 /* 346 * Read data.504 * Wait a bit for the receivers to finish up. 347 505 */ 348 while (INTNETRingHasMoreToRead(&pArgs->pBuf->Recv)) 506 unsigned cYields = 100000; 507 while ( ( INTNETRingHasMoreToRead(&pThis->pBuf0->Recv) 508 || INTNETRingHasMoreToRead(&pThis->pBuf1->Recv)) 509 && cYields-- > 0) 510 RTThreadYield(); 511 512 uint64_t u64Elapsed = RT_MAX(Args0.u64End, Args1.u64End) - RT_MIN(Args0.u64Start, Args1.u64Start); 513 uint64_t u64Speed = (uint64_t)((2 * g_cbTransfer / 1024) / (u64Elapsed / 1000000000.0)); 514 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, 515 "transfered %u bytes in %'RU64 ns (%'RU64 KB/s)\n", 516 2 * g_cbTransfer, u64Elapsed, u64Speed); 517 518 /* 519 * Wait for the threads to finish up... 520 */ 521 RTTESTI_CHECK_RC_OK(rc = RTThreadWait(ThreadRecv0, 5000, &rc2)); 522 if (RT_SUCCESS(rc)) 349 523 { 350 uint8_t abBuf[16384]; 351 uint32_t cb = INTNETRingReadAndSkipFrame(&pArgs->pBuf->Recv, abBuf); 352 unsigned *puFrame = (unsigned *)&abBuf[sizeof(RTMAC) * 2]; 353 354 /* check for termination frame. */ 355 if ( cb == sizeof(RTMAC) * 2 + sizeof(unsigned) * 4 356 && puFrame[0] == 0xffffdead 357 && puFrame[1] == 0xffffdead 358 && puFrame[2] == 0xffffdead 359 && puFrame[3] == 0xffffdead) 360 { 361 pArgs->u64End = RTTimeNanoTS(); 362 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs terminating.\n" 363 "tstIntNetR0: iFrame=%u cb=%'u c=%'u %'uKB/s %'ufps cLost=%'u \n", 364 &pArgs->Mac, iFrame, cbReceived, iFrame - cLostFrames, 365 (unsigned)(cbReceived * 1000000000.0 / 1024 / (pArgs->u64End - pArgs->u64Start)), 366 (unsigned)((iFrame - cLostFrames) * 1000000000.0 / (pArgs->u64End - pArgs->u64Start)), 367 cLostFrames); 368 return VINF_SUCCESS; 369 } 370 371 /* validate frame header */ 372 PRTMAC pMacSrc = (PRTMAC)&abBuf[0]; 373 PRTMAC pMacDst = pMacSrc + 1; 374 if ( pMacDst->au16[0] != 0x8086 375 || pMacDst->au16[1] != 0 376 || pMacDst->au16[2] != pArgs->Mac.au16[2] 377 || pMacSrc->au16[0] != 0x8086 378 || pMacSrc->au16[1] != 0 379 || pMacSrc->au16[2] == pArgs->Mac.au16[2]) 380 { 381 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs received frame header: %.16Rhxs\n", 382 &pArgs->Mac, abBuf); 383 g_cErrors++; 384 } 385 386 /* frame stuff and stats. */ 387 int off = iFrame + 1 - *puFrame; 388 if (off) 389 { 390 if (off > 0) 391 { 392 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs: iFrame=%d *puFrame=%d off=%d\n", 393 &pArgs->Mac, iFrame, *puFrame, off); 394 g_cErrors++; 395 cLostFrames++; 396 } 397 else 398 { 399 cLostFrames += -off; 400 #ifndef IGNORE_LOST_FRAMES 401 if (off < 50) 402 { 403 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs: iFrame=%d *puFrame=%d off=%d\n", 404 &pArgs->Mac, iFrame, *puFrame, off); 405 g_cErrors++; 406 } 407 #endif 408 } 409 } 410 iFrame = *puFrame; 411 cbReceived += cb; 524 RTTESTI_CHECK_RC_OK(rc2); 525 ThreadRecv0 = NIL_RTTHREAD; 412 526 } 413 } 414 } 527 528 RTTESTI_CHECK_RC_OK(rc = RTThreadWait(ThreadRecv1, 5000, &rc2)); 529 if (RT_SUCCESS(rc)) 530 { 531 RTTESTI_CHECK_RC_OK(rc2); 532 ThreadRecv1 = NIL_RTTHREAD; 533 } 534 } 535 536 /* 537 * Give them a chance to complete... 538 */ 539 RTThreadWait(ThreadRecv0, 5000, NULL); 540 RTThreadWait(ThreadRecv1, 5000, NULL); 541 RTThreadWait(ThreadSend0, 5000, NULL); 542 RTThreadWait(ThreadSend1, 5000, NULL); 543 544 545 /* 546 * Display statistics. 547 */ 548 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, 549 "Buf0: Yields-OK=%llu Yields-NOK=%llu Lost=%llu Bad=%llu\n", 550 pThis->pBuf0->cStatYieldsOk.c, 551 pThis->pBuf0->cStatYieldsNok.c, 552 pThis->pBuf0->cStatLost.c, 553 pThis->pBuf0->cStatBadFrames.c); 554 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, 555 "Buf0.Recv: Frames=%llu Bytes=%llu Overflows=%llu\n", 556 pThis->pBuf0->Recv.cStatFrames, 557 pThis->pBuf0->Recv.cbStatWritten.c, 558 pThis->pBuf0->Recv.cOverflows.c); 559 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, 560 "Buf0.Send: Frames=%llu Bytes=%llu Overflows=%llu\n", 561 pThis->pBuf0->Send.cStatFrames, 562 pThis->pBuf0->Send.cbStatWritten.c, 563 pThis->pBuf0->Send.cOverflows.c); 564 565 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, 566 "Buf1: Yields-OK=%llu Yields-NOK=%llu Lost=%llu Bad=%llu\n", 567 pThis->pBuf1->cStatYieldsOk.c, 568 pThis->pBuf1->cStatYieldsNok.c, 569 pThis->pBuf1->cStatLost.c, 570 pThis->pBuf1->cStatBadFrames.c); 571 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, 572 "Buf1.Recv: Frames=%llu Bytes=%llu Overflows=%llu\n", 573 pThis->pBuf1->Recv.cStatFrames, 574 pThis->pBuf1->Recv.cbStatWritten.c, 575 pThis->pBuf1->Recv.cOverflows.c); 576 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, 577 "Buf1.Send: Frames=%llu Bytes=%llu Overflows=%llu\n", 578 pThis->pBuf1->Send.cStatFrames, 579 pThis->pBuf1->Send.cbStatWritten.c, 580 pThis->pBuf1->Send.cOverflows.c); 581 582 } 583 584 /** 585 * Performs a simple broadcast test. 586 * 587 * @param pThis The test instance. 588 * @param fHeadGuard Whether to use a head or tail guard. 589 */ 590 static void doBroadcastTest(PTSTSTATE pThis, bool fHeadGuard) 591 { 592 static uint16_t const s_au16Frame[7] = { /* dst:*/ 0xffff, 0xffff, 0xffff, /*src:*/0x8086, 0, 0, 0x0800 }; 593 594 RTTESTI_CHECK_RC_RETV(tstIntNetSendBuf(pThis->pIntNet, &pThis->pBuf0->Send, pThis->hIf0, 595 g_pSession, &s_au16Frame, sizeof(s_au16Frame)), 596 VINF_SUCCESS); 597 598 /* No echo, please */ 599 RTTESTI_CHECK_RC_RETV(INTNETR0IfWait(pThis->pIntNet, pThis->hIf0, g_pSession, 1), VERR_TIMEOUT); 600 601 /* The other interface should see it though. But Wait should only return once, thank you. */ 602 RTTESTI_CHECK_RC_RETV(INTNETR0IfWait(pThis->pIntNet, pThis->hIf1, g_pSession, 1), VINF_SUCCESS); 603 RTTESTI_CHECK_RC_RETV(INTNETR0IfWait(pThis->pIntNet, pThis->hIf1, g_pSession, 0), VERR_TIMEOUT); 604 605 /* Receive the data. */ 606 const unsigned cbExpect = RT_ALIGN(sizeof(s_au16Frame) + sizeof(INTNETHDR), sizeof(INTNETHDR)); 607 RTTESTI_CHECK_MSG(INTNETRingGetReadable(&pThis->pBuf1->Recv) == cbExpect, 608 ("%#x vs. %#x\n", INTNETRingGetReadable(&pThis->pBuf1->Recv), cbExpect)); 609 610 void *pvBuf; 611 RTTESTI_CHECK_RC_OK_RETV(RTTestGuardedAlloc(g_hTest, sizeof(s_au16Frame), 1, fHeadGuard, &pvBuf)); 612 uint32_t cb; 613 RTTESTI_CHECK_MSG_RETV((cb = INTNETRingReadAndSkipFrame(&pThis->pBuf1->Recv, pvBuf)) == sizeof(s_au16Frame), 614 ("%#x vs. %#x\n", cb, sizeof(s_au16Frame))); 615 616 if (memcmp(pvBuf, &s_au16Frame, sizeof(s_au16Frame))) 617 RTTestIFailed("Got invalid data!\n" 618 "received: %.*Rhxs\n" 619 "expected: %.*Rhxs\n", 620 cb, pvBuf, sizeof(s_au16Frame), &s_au16Frame); 621 } 622 623 /** 624 * Performs a simple unicast test. 625 * 626 * @param pThis The test instance. 627 * @param fHeadGuard Whether to use a head or tail guard. 628 */ 629 static void doUnicastTest(PTSTSTATE pThis, bool fHeadGuard) 630 { 631 static uint16_t const s_au16Frame[7] = { /* dst:*/ 0x8086, 0, 0, /*src:*/0x8086, 0, 1, 0x0800 }; 632 633 RTTESTI_CHECK_RC_RETV(tstIntNetSendBuf(pThis->pIntNet, &pThis->pBuf1->Send, pThis->hIf1, 634 g_pSession, s_au16Frame, sizeof(s_au16Frame)), 635 VINF_SUCCESS); 636 637 /* No echo, please */ 638 RTTESTI_CHECK_RC_RETV(INTNETR0IfWait(pThis->pIntNet, pThis->hIf1, g_pSession, 1), VERR_TIMEOUT); 639 640 /* The other interface should see it though. But Wait should only return once, thank you. */ 641 RTTESTI_CHECK_RC_RETV(INTNETR0IfWait(pThis->pIntNet, pThis->hIf0, g_pSession, 1), VINF_SUCCESS); 642 RTTESTI_CHECK_RC_RETV(INTNETR0IfWait(pThis->pIntNet, pThis->hIf0, g_pSession, 0), VERR_TIMEOUT); 643 644 /* Receive the data. */ 645 const unsigned cbExpect = RT_ALIGN(sizeof(s_au16Frame) + sizeof(INTNETHDR), sizeof(INTNETHDR)); 646 RTTESTI_CHECK_MSG(INTNETRingGetReadable(&pThis->pBuf0->Recv) == cbExpect, 647 ("%#x vs. %#x\n", INTNETRingGetReadable(&pThis->pBuf0->Recv), cbExpect)); 648 649 void *pvBuf; 650 RTTESTI_CHECK_RC_OK_RETV(RTTestGuardedAlloc(g_hTest, sizeof(s_au16Frame), 1, fHeadGuard, &pvBuf)); 651 uint32_t cb; 652 RTTESTI_CHECK_MSG_RETV((cb = INTNETRingReadAndSkipFrame(&pThis->pBuf0->Recv, pvBuf)) == sizeof(s_au16Frame), 653 ("%#x vs. %#x\n", cb, sizeof(s_au16Frame))); 654 655 if (memcmp(pvBuf, &s_au16Frame, sizeof(s_au16Frame))) 656 RTTestIFailed("Got invalid data!\n" 657 "received: %.*Rhxs\n" 658 "expected: %.*Rhxs\n", 659 cb, pvBuf, sizeof(s_au16Frame), s_au16Frame); 660 } 661 662 static void doTest(PTSTSTATE pThis, uint32_t cbRecv, uint32_t cbSend) 663 { 664 665 /* 666 * Create an INTNET instance. 667 */ 668 RTTestISub("INTNETR0Create"); 669 RTTESTI_CHECK_RC_RETV(INTNETR0Create(&pThis->pIntNet), VINF_SUCCESS); 670 671 /* 672 * Create two interfaces and activate them. 673 */ 674 RTTestISub("Network creation"); 675 int rc = tstOpenInterfaces(pThis, "test", cbSend, cbRecv); 676 if (RT_FAILURE(rc)) 677 return; 678 RTTESTI_CHECK_RC(INTNETR0IfSetActive(pThis->pIntNet, pThis->hIf0, g_pSession, true), VINF_SUCCESS); 679 RTTESTI_CHECK_RC(INTNETR0IfSetActive(pThis->pIntNet, pThis->hIf1, g_pSession, true), VINF_SUCCESS); 680 681 /* 682 * Test basic waiting. 683 */ 684 RTTestISub("INTNETR0IfWait"); 685 RTTESTI_CHECK_RC(INTNETR0IfWait(pThis->pIntNet, pThis->hIf0, g_pSession, 1), VERR_TIMEOUT); 686 RTTESTI_CHECK_RC(INTNETR0IfWait(pThis->pIntNet, pThis->hIf0, g_pSession, 0), VERR_TIMEOUT); 687 RTTESTI_CHECK_RC(INTNETR0IfWait(pThis->pIntNet, pThis->hIf1, g_pSession, 1), VERR_TIMEOUT); 688 RTTESTI_CHECK_RC(INTNETR0IfWait(pThis->pIntNet, pThis->hIf1, g_pSession, 0), VERR_TIMEOUT); 689 690 /* 691 * Broadcast send and receive. 692 * (This establishes the MAC address of the 1st interface.) 693 */ 694 RTTestISub("Broadcast"); 695 doBroadcastTest(pThis, false /*fHeadGuard*/); 696 doBroadcastTest(pThis, true /*fHeadGuard*/); 697 698 /* 699 * Unicast send and receive. 700 * (This establishes the MAC address of the 2nd interface.) 701 */ 702 RTTestISub("Unicast"); 703 doUnicastTest(pThis, false /*fHeadGuard*/); 704 doUnicastTest(pThis, true /*fHeadGuard*/); 705 706 /* 707 * Do the big bi-directional transfer test if the basics worked out. 708 */ 709 if (!RTTestIErrorCount()) 710 { 711 RTTestISubF("bi-directional benchmark, cbSend=%u, cbRecv=%u, cbTransfer=%u", 712 pThis->pBuf0->cbSend, pThis->pBuf0->cbRecv, g_cbTransfer); 713 tstBidirectionalTransfer(pThis); 714 } 715 716 /* 717 * Destroy the service. 718 */ 719 tstCloseInterfaces(pThis); 720 INTNETR0Destroy(pThis->pIntNet); 721 } 722 415 723 416 724 int main(int argc, char **argv) 417 725 { 418 /* 419 * Init the runtime and parse arguments. 420 */ 421 RTR3Init(); 422 726 int rc = RTTestInitAndCreate("tstIntNetR0", &g_hTest); 727 if (rc) 728 return rc; 729 730 /* 731 * Parse the arguments. 732 */ 423 733 static RTGETOPTDEF const s_aOptions[] = 424 734 { 425 { "--recv-buffer", 'r', RTGETOPT_REQ_UINT32 }, 426 { "--send-buffer", 's', RTGETOPT_REQ_UINT32 }, 735 { "--recv-buffer", 'r', RTGETOPT_REQ_UINT32 }, 736 { "--send-buffer", 's', RTGETOPT_REQ_UINT32 }, 737 { "--transfer-size", 'l', RTGETOPT_REQ_UINT32 }, 427 738 }; 428 739 429 uint32_t cb Recv = 32 * _1K;430 uint32_t cb Send = 1536*2;740 uint32_t cbSend = 1536*2 + 4; 741 uint32_t cbRecv = 0x8000; 431 742 432 743 int ch; … … 437 748 switch (ch) 438 749 { 750 case 'l': 751 g_cbTransfer = Value.u32; 752 break; 753 439 754 case 'r': 440 755 cbRecv = Value.u32; … … 450 765 451 766 /* 452 * Create an INTNET instance. 453 */ 454 RTPrintf("tstIntNetR0: TESTING cbSend=%d cbRecv=%d ...\n", cbSend, cbRecv); 455 PINTNET pIntNet; 456 int rc = INTNETR0Create(&pIntNet); 457 if (RT_FAILURE(rc)) 458 { 459 RTPrintf("tstIntNetR0: INTNETR0Create failed, rc=%Rrc\n"); 460 return 1; 461 } 462 463 /* 464 * Create two interfaces. 465 */ 466 INTNETIFHANDLE hIf0 = INTNET_HANDLE_INVALID; 467 rc = INTNETR0Open(pIntNet, g_pSession, "test", kIntNetTrunkType_None, "", 0, 1536*2 + 4, 0x8000, &hIf0); 468 if (RT_SUCCESS(rc)) 469 { 470 if (hIf0 != INTNET_HANDLE_INVALID) 471 { 472 INTNETIFHANDLE hIf1 = INTNET_HANDLE_INVALID; 473 rc = INTNETR0Open(pIntNet, g_pSession, "test", kIntNetTrunkType_None, NULL, 0, 1536*2 + 4, 0x8000, &hIf1); 474 if (RT_SUCCESS(rc)) 475 { 476 if (hIf1 != INTNET_HANDLE_INVALID) 477 { 478 PINTNETBUF pBuf0; 479 rc = INTNETR0IfGetRing0Buffer(pIntNet, hIf0, g_pSession, &pBuf0); 480 if (RT_FAILURE(rc) || !pBuf0) 481 { 482 RTPrintf("tstIntNetR0: INTNETIfGetRing0Buffer failed! pBuf0=%p rc=%Rrc\n", pBuf0, rc); 483 g_cErrors++; 484 } 485 PINTNETBUF pBuf1; 486 rc = INTNETR0IfGetRing0Buffer(pIntNet, hIf1, g_pSession, &pBuf1); 487 if (RT_FAILURE(rc)) 488 { 489 RTPrintf("tstIntNetR0: INTNETIfGetRing0Buffer failed! pBuf1=%p rc=%Rrc\n", pBuf1, rc); 490 g_cErrors++; 491 } 492 493 rc = INTNETR0IfSetActive(pIntNet, hIf0, g_pSession, true); 494 if (RT_FAILURE(rc)) 495 { 496 RTPrintf("tstIntNetR0: INTNETR0IfSetActive failed! rc=%Rrc\n", rc); 497 g_cErrors++; 498 } 499 rc = INTNETR0IfSetActive(pIntNet, hIf1, g_pSession, true); 500 if (RT_FAILURE(rc)) 501 { 502 RTPrintf("tstIntNetR0: INTNETR0IfSetActive failed! rc=%Rrc\n", rc); 503 g_cErrors++; 504 } 505 506 507 /* 508 * Test basic waiting. 509 */ 510 rc = INTNETR0IfWait(pIntNet, hIf0, g_pSession, 1); 511 if (rc != VERR_TIMEOUT) 512 { 513 RTPrintf("tstIntNetR0: INTNETIfWait returned %Rrc expected VERR_TIMEOUT (hIf0)\n", rc); 514 g_cErrors++; 515 } 516 rc = INTNETR0IfWait(pIntNet, hIf1, g_pSession, 0); 517 if (rc != VERR_TIMEOUT) 518 { 519 RTPrintf("tstIntNetR0: INTNETIfWait returned %Rrc expected VERR_TIMEOUT (hIf1)\n", rc); 520 g_cErrors++; 521 } 522 523 /* 524 * Send and receive. 525 */ 526 rc = tstIntNetSendBuf(pIntNet, &pBuf0->Send, hIf0, g_pSession, &g_TestFrame0, sizeof(g_TestFrame0)); 527 if (RT_SUCCESS(rc)) 528 { 529 rc = INTNETR0IfWait(pIntNet, hIf0, g_pSession, 1); 530 if (rc != VERR_TIMEOUT) 531 { 532 RTPrintf("tstIntNetR0: INTNETIfWait returned %Rrc expected VERR_TIMEOUT (hIf0, 2nd)\n", rc); 533 g_cErrors++; 534 } 535 rc = INTNETR0IfWait(pIntNet, hIf1, g_pSession, 0); 536 if (rc == VINF_SUCCESS) 537 { 538 /* receive it */ 539 uint8_t abBuf[sizeof(g_TestFrame0)]; 540 const unsigned cbExpect = RT_ALIGN(sizeof(g_TestFrame0) + sizeof(INTNETHDR), sizeof(INTNETHDR)); 541 if (INTNETRingGetReadable(&pBuf1->Recv) != cbExpect) 542 { 543 RTPrintf("tstIntNetR0: %d readable bytes, expected %d!\n", INTNETRingGetReadable(&pBuf1->Recv), cbExpect); 544 g_cErrors++; 545 } 546 uint32_t cb = INTNETRingReadAndSkipFrame(&pBuf1->Recv, abBuf); 547 if (cb != sizeof(g_TestFrame0)) 548 { 549 RTPrintf("tstIntNetR0: read %d frame bytes, expected %d!\n", cb, sizeof(g_TestFrame0)); 550 g_cErrors++; 551 } 552 else if (memcmp(abBuf, &g_TestFrame0, sizeof(g_TestFrame0))) 553 { 554 RTPrintf("tstIntNetR0: Got invalid data!\n" 555 "received: %.*Rhxs\n" 556 "expected: %.*Rhxs\n", 557 cb, abBuf, sizeof(g_TestFrame0), &g_TestFrame0); 558 g_cErrors++; 559 } 560 561 /* 562 * Send a packet from If1 just to set its MAC address. 563 */ 564 rc = tstIntNetSendBuf(pIntNet, &pBuf1->Send, hIf1, g_pSession, &g_TestFrame1, sizeof(g_TestFrame1)); 565 if (RT_FAILURE(rc)) 566 { 567 RTPrintf("tstIntNetR0: INTNETIfSend returned %Rrc! (hIf1)\n", rc); 568 g_cErrors++; 569 } 570 571 572 /* 573 * Start threaded testcase. 574 * Give it 5 mins to finish. 575 */ 576 if (!g_cErrors) 577 { 578 MYARGS Args0; 579 RT_ZERO(Args0); 580 Args0.hIf = hIf0; 581 Args0.pBuf = pBuf0; 582 Args0.pIntNet = pIntNet; 583 Args0.Mac.au16[0] = 0x8086; 584 Args0.Mac.au16[1] = 0; 585 Args0.Mac.au16[2] = 0; 586 587 MYARGS Args1; 588 RT_ZERO(Args1); 589 Args1.hIf = hIf1; 590 Args1.pBuf = pBuf1; 591 Args1.pIntNet = pIntNet; 592 Args1.Mac.au16[0] = 0x8086; 593 Args1.Mac.au16[1] = 0; 594 Args1.Mac.au16[2] = 1; 595 596 RTTHREAD ThreadRecv0 = NIL_RTTHREAD; 597 RTTHREAD ThreadRecv1 = NIL_RTTHREAD; 598 RTTHREAD ThreadSend0 = NIL_RTTHREAD; 599 RTTHREAD ThreadSend1 = NIL_RTTHREAD; 600 rc = RTThreadCreate(&ThreadRecv0, ReceiveThread, &Args0, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "RECV0"); 601 if (RT_SUCCESS(rc)) 602 rc = RTThreadCreate(&ThreadRecv1, ReceiveThread, &Args1, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "RECV1"); 603 if (RT_SUCCESS(rc)) 604 rc = RTThreadCreate(&ThreadSend0, SendThread, &Args0, 0, RTTHREADTYPE_EMULATION, RTTHREADFLAGS_WAITABLE, "SEND0"); 605 if (RT_SUCCESS(rc)) 606 rc = RTThreadCreate(&ThreadSend1, SendThread, &Args1, 0, RTTHREADTYPE_EMULATION, RTTHREADFLAGS_WAITABLE, "SEND1"); 607 if (RT_SUCCESS(rc)) 608 { 609 int rc2 = VINF_SUCCESS; 610 rc = RTThreadWait(ThreadSend0, 5*60*1000, &rc2); 611 AssertRC(rc); 612 if (RT_SUCCESS(rc)) 613 { 614 ThreadSend0 = NIL_RTTHREAD; 615 rc = RTThreadWait(ThreadSend1, 5*60*1000, RT_SUCCESS(rc2) ? &rc2 : NULL); 616 AssertRC(rc); 617 if (RT_SUCCESS(rc)) 618 ThreadSend1 = NIL_RTTHREAD; 619 } 620 if ( RT_SUCCESS(rc) 621 && RT_SUCCESS(rc2)) 622 { 623 /* 624 * Wait a bit for the receivers to finish up. 625 */ 626 unsigned cYields = 100000; 627 while ( ( INTNETRingHasMoreToRead(&pBuf0->Recv) 628 || INTNETRingHasMoreToRead(&pBuf1->Recv)) 629 && cYields-- > 0) 630 RTThreadYield(); 631 632 uint64_t u64Elapsed = RT_MAX(Args0.u64End, Args1.u64End) - RT_MIN(Args0.u64Start, Args1.u64Start); 633 uint64_t u64Speed = (uint64_t)((2 * TEST_TRANSFER_SIZE / 1024) / (u64Elapsed / 1000000000.0)); 634 RTPrintf("tstIntNetR0: transfered %d bytes in %'RU64 ns (%'RU64 KB/s)\n", 635 2 * TEST_TRANSFER_SIZE, u64Elapsed, u64Speed); 636 637 /* 638 * Closing time... 639 */ 640 rc = RTThreadWait(ThreadRecv0, 5000, &rc2); 641 if (RT_SUCCESS(rc)) 642 ThreadRecv0 = NIL_RTTHREAD; 643 if (RT_FAILURE(rc) || RT_FAILURE(rc2)) 644 { 645 RTPrintf("tstIntNetR0: Failed waiting on receiver thread 0, rc=%Rrc, rc2=%Rrc\n", rc, rc2); 646 g_cErrors++; 647 } 648 649 rc = RTThreadWait(ThreadRecv1, 5000, &rc2); 650 if (RT_SUCCESS(rc)) 651 ThreadRecv1 = NIL_RTTHREAD; 652 if (RT_FAILURE(rc) || RT_FAILURE(rc2)) 653 { 654 RTPrintf("tstIntNetR0: Failed waiting on receiver thread 1, rc=%Rrc, rc2=%Rrc\n", rc, rc2); 655 g_cErrors++; 656 } 657 658 rc = INTNETR0IfClose(pIntNet, hIf0, g_pSession); 659 if (RT_SUCCESS(rc)) 660 { 661 hIf0 = INTNET_HANDLE_INVALID; 662 pBuf0 = NULL; 663 } 664 else 665 { 666 RTPrintf("tstIntNetR0: INTNETIfClose failed, rc=%Rrc! (hIf0)\n", rc); 667 g_cErrors++; 668 } 669 670 rc = INTNETR0IfClose(pIntNet, hIf1, g_pSession); 671 if (RT_SUCCESS(rc)) 672 { 673 hIf1 = INTNET_HANDLE_INVALID; 674 pBuf1 = NULL; 675 } 676 else 677 { 678 RTPrintf("tstIntNetR0: INTNETIfClose failed, rc=%Rrc! (hIf1)\n", rc); 679 g_cErrors++; 680 } 681 682 683 /* check if the network still exist... */ 684 if (pIntNet->pNetworks) 685 { 686 RTPrintf("tstIntNetR0: The network wasn't deleted! (g_cErrors=%d)\n", g_cErrors); 687 g_cErrors++; 688 } 689 } 690 else 691 { 692 RTPrintf("tstIntNetR0: Waiting on senders failed, rc=%Rrc, rc2=%Rrc\n", rc, rc2); 693 g_cErrors++; 694 } 695 696 /* 697 * Give them a chance to complete... 698 */ 699 RTThreadWait(ThreadRecv0, 5000, NULL); 700 RTThreadWait(ThreadRecv1, 5000, NULL); 701 RTThreadWait(ThreadSend0, 5000, NULL); 702 RTThreadWait(ThreadSend1, 5000, NULL); 703 704 } 705 else 706 { 707 RTPrintf("tstIntNetR0: Failed to create threads, rc=%Rrc\n", rc); 708 g_cErrors++; 709 } 710 } 711 } 712 else 713 { 714 RTPrintf("tstIntNetR0: INTNETIfWait returned %Rrc expected VINF_SUCCESS (hIf1)\n", rc); 715 g_cErrors++; 716 } 717 } 718 else 719 { 720 RTPrintf("tstIntNetR0: INTNETIfSend returned %Rrc! (hIf0)\n", rc); 721 g_cErrors++; 722 } 723 } 724 else 725 { 726 RTPrintf("tstIntNetR0: INTNETOpen returned invalid handle on success! (hIf1)\n"); 727 g_cErrors++; 728 } 729 730 if (hIf1 != INTNET_HANDLE_INVALID) 731 rc = INTNETR0IfClose(pIntNet, hIf1, g_pSession); 732 } 733 else 734 { 735 RTPrintf("tstIntNetR0: INTNETOpen failed for the 2nd interface! rc=%Rrc\n", rc); 736 g_cErrors++; 737 } 738 739 if (hIf0 != INTNET_HANDLE_INVALID) 740 rc = INTNETR0IfClose(pIntNet, hIf0, g_pSession); 741 } 742 else 743 { 744 RTPrintf("tstIntNetR0: INTNETOpen returned invalid handle on success! (hIf0)\n"); 745 g_cErrors++; 746 } 747 } 748 else 749 { 750 RTPrintf("tstIntNetR0: INTNETOpen failed for the 1st interface! rc=%Rrc\n", rc); 751 g_cErrors++; 752 } 753 754 /* 755 * Destroy the service. 756 */ 757 INTNETR0Destroy(pIntNet); 758 759 /* 760 * Summary. 761 */ 762 if (!g_cErrors) 763 RTPrintf("tstIntNetR0: SUCCESS\n"); 764 else 765 RTPrintf("tstIntNetR0: FAILURE - %d errors\n", g_cErrors); 766 767 return !!g_cErrors; 768 } 769 767 * Do the testing and report summary. 768 */ 769 TSTSTATE This; 770 RT_ZERO(This); 771 doTest(&This, cbRecv, cbSend); 772 773 return RTTestSummaryAndDestroy(g_hTest); 774 } 775 -
trunk/src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFlt.c
r28088 r28623 427 427 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION); 428 428 Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected); 429 /** @todo Assert(pThis->fActive); - disabled because we may call this without 430 * holding the out-bound lock and race the clearing. */ 429 /* No fActive check here. */ 431 430 432 431 /* … … 450 449 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION); 451 450 Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected); 452 Assert(pThis->fActive);451 /* No fActive check here. */ 453 452 454 453 /*
Note:
See TracChangeset
for help on using the changeset viewer.