VirtualBox

Changeset 57600 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Sep 2, 2015 4:42:05 PM (10 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
102461
Message:

NAT: don't deadlock if we try to activate a NAT network while the VM is not running

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Network/DrvNAT.cpp

    r57442 r57600  
    575575        PDMDrvHlpFTSetCheckpoint(pThis->pDrvIns, FTMCHECKPOINTTYPE_NETWORK);
    576576
    577 
    578         RTREQQUEUE hQueue = pThis->hSlirpReqQueue;
    579 
    580         rc = RTReqQueueCallEx(hQueue, NULL /*ppReq*/, 0 /*cMillies*/, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
     577        rc = RTReqQueueCallEx(pThis->hSlirpReqQueue, NULL /*ppReq*/, 0 /*cMillies*/,
     578                              RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
    581579                              (PFNRT)drvNATSendWorker, 2, pThis, pSgBuf);
    582580        if (RT_SUCCESS(rc))
     
    667665    LogFlow(("drvNATNetworkUp_NotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
    668666
    669     /* Don't queue new requests when the NAT thread is about to stop.
    670      * But the VM could also be paused. So memorize the desired state. */
     667    /* Don't queue new requests if the NAT thread is not running (e.g. paused,
     668     * stopping), otherwise we would deadlock. Memorize the change. */
    671669    if (pThis->pSlirpThread->enmState != PDMTHREADSTATE_RUNNING)
    672670    {
     
    678676    int rc = RTReqQueueCallEx(pThis->hSlirpReqQueue, &pReq, 0 /*cMillies*/, RTREQFLAGS_VOID,
    679677                              (PFNRT)drvNATNotifyLinkChangedWorker, 2, pThis, enmLinkState);
    680     if (RT_LIKELY(rc == VERR_TIMEOUT))
     678    if (rc == VERR_TIMEOUT)
    681679    {
    682680        drvNATNotifyNATThread(pThis, "drvNATNetworkUp_NotifyLinkChanged");
     
    714712}
    715713
    716 static DECLCALLBACK(int) drvNATNetworkNatConfig_RedirectRuleCommand(PPDMINETWORKNATCONFIG pInterface, bool fRemove,
    717                                                              bool fUdp, const char *pHostIp,
    718                                                              uint16_t u16HostPort, const char *pGuestIp, uint16_t u16GuestPort)
     714static DECLCALLBACK(int) drvNATNetworkNatConfigRedirect(PPDMINETWORKNATCONFIG pInterface, bool fRemove,
     715                                                        bool fUdp, const char *pHostIp, uint16_t u16HostPort,
     716                                                        const char *pGuestIp, uint16_t u16GuestPort)
    719717{
    720718    LogFlowFunc(("fRemove=%d, fUdp=%d, pHostIp=%s, u16HostPort=%u, pGuestIp=%s, u16GuestPort=%u\n",
    721                  RT_BOOL(fRemove), RT_BOOL(fUdp), pHostIp, u16HostPort, pGuestIp,
    722                  u16GuestPort));
     719                 RT_BOOL(fRemove), RT_BOOL(fUdp), pHostIp, u16HostPort, pGuestIp, u16GuestPort));
    723720    PDRVNAT pThis = RT_FROM_MEMBER(pInterface, DRVNAT, INetworkNATCfg);
    724     PRTREQ pReq;
    725     int rc = RTReqQueueCallEx(pThis->hSlirpReqQueue, &pReq, 0 /*cMillies*/, RTREQFLAGS_VOID,
     721    /* Execute the command directly if the VM is not running. */
     722    int rc;
     723    if (pThis->pSlirpThread->enmState != PDMTHREADSTATE_RUNNING)
     724    {
     725        drvNATNotifyApplyPortForwardCommand(pThis, fRemove, fUdp, pHostIp,
     726                                           u16HostPort, pGuestIp,u16GuestPort);
     727        rc = VINF_SUCCESS;
     728    }
     729    else
     730    {
     731        PRTREQ pReq;
     732        rc = RTReqQueueCallEx(pThis->hSlirpReqQueue, &pReq, 0 /*cMillies*/, RTREQFLAGS_VOID,
    726733                              (PFNRT)drvNATNotifyApplyPortForwardCommand, 7, pThis, fRemove,
    727734                              fUdp, pHostIp, u16HostPort, pGuestIp, u16GuestPort);
    728     if (RT_LIKELY(rc == VERR_TIMEOUT))
    729     {
    730         drvNATNotifyNATThread(pThis, "drvNATNetworkNatConfig_RedirectRuleCommand");
    731         rc = RTReqWait(pReq, RT_INDEFINITE_WAIT);
    732         AssertRC(rc);
    733     }
    734     else
    735         AssertRC(rc);
    736 
    737     RTReqRelease(pReq);
    738     port_forwarding_done:
     735        if (rc == VERR_TIMEOUT)
     736        {
     737            drvNATNotifyNATThread(pThis, "drvNATNetworkNatConfigRedirect");
     738            rc = RTReqWait(pReq, RT_INDEFINITE_WAIT);
     739            AssertRC(rc);
     740        }
     741        else
     742            AssertRC(rc);
     743
     744        RTReqRelease(pReq);
     745    }
    739746    return rc;
    740747}
     
    11431150    switch (strategy)
    11441151    {
    1145 
    11461152        case VBOX_NAT_DNS_DNSPROXY:
    1147             {
    1148                 /**
    1149                  * XXX: Here or in _strategy_selector we should deal with network change
    1150                  * in "network change" scenario domain name change we have to update guest lease
    1151                  * forcibly.
    1152                  * Note at that built-in dhcp also updates DNS information on NAT thread.
    1153                  */
    1154                 /**
    1155                  * It's unsafe to to do it directly on non-NAT thread
    1156                  * so we schedule the worker and kick the NAT thread.
    1157                  */
    1158                 RTREQQUEUE hQueue = pThis->hSlirpReqQueue;
    1159 
    1160                 int rc = RTReqQueueCallEx(hQueue, NULL /*ppReq*/, 0 /*cMillies*/,
    1161                                           RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
    1162                                           (PFNRT)drvNATReinitializeHostNameResolving, 1, pThis);
    1163                 if (RT_SUCCESS(rc))
    1164                     drvNATNotifyNATThread(pThis, "drvNATUpdateDNS");
    1165 
    1166                 return;
    1167             }
     1153        {
     1154            /**
     1155             * XXX: Here or in _strategy_selector we should deal with network change
     1156             * in "network change" scenario domain name change we have to update guest lease
     1157             * forcibly.
     1158             * Note at that built-in dhcp also updates DNS information on NAT thread.
     1159             */
     1160            /**
     1161             * It's unsafe to to do it directly on non-NAT thread
     1162             * so we schedule the worker and kick the NAT thread.
     1163             */
     1164            int rc = RTReqQueueCallEx(pThis->hSlirpReqQueue, NULL /*ppReq*/, 0 /*cMillies*/,
     1165                                      RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
     1166                                      (PFNRT)drvNATReinitializeHostNameResolving, 1, pThis);
     1167            if (RT_SUCCESS(rc))
     1168                drvNATNotifyNATThread(pThis, "drvNATUpdateDNS");
     1169
     1170            return;
     1171        }
    11681172
    11691173        case VBOX_NAT_DNS_EXTERNAL:
     
    11721176             * Disconnect the guest from the network temporarily to let it pick up the changes.
    11731177             */
    1174 
    11751178            if (fFlapLink)
    11761179                pThis->pIAboveConfig->pfnSetLinkState(pThis->pIAboveConfig,
     
    14211424
    14221425    /* NAT engine configuration */
    1423     pThis->INetworkNATCfg.pfnRedirectRuleCommand = drvNATNetworkNatConfig_RedirectRuleCommand;
     1426    pThis->INetworkNATCfg.pfnRedirectRuleCommand = drvNATNetworkNatConfigRedirect;
    14241427#if HAVE_NOTIFICATION_FOR_DNS_UPDATE && !defined(RT_OS_DARWIN)
    14251428    /*
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette