VirtualBox

Changeset 14526 in vbox for trunk


Ignore:
Timestamp:
Nov 24, 2008 3:16:01 PM (16 years ago)
Author:
vboxsync
Message:

Devices/Storage: iSCSI stuff, including bringing IntNet support back to life. Should build, but otherwise untested.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/VBoxHDD-new.h

    r13988 r14526  
    216216 * provide the mandatory configuration parts this way. */
    217217#define VD_CAP_CONFIG               RT_BIT(7)
     218/** The backend uses the network stack interface. The caller has to provide
     219 * the appropriate interface. */
     220#define VD_CAP_TCPNET               RT_BIT(8)
    218221/** @}*/
    219222
     
    233236    /** Interface for configuration information. Per-image. */
    234237    VDINTERFACETYPE_CONFIG,
     238    /** Interface for TCP network stack. Per-disk. */
     239    VDINTERFACETYPE_TCPNET,
    235240    /** invalid interface. */
    236241    VDINTERFACETYPE_INVALID
     
    252257    /** Opaque user data which is passed on every call. */
    253258    void               *pvUser;
    254     /** Pointer to the function call table of the interface. 
     259    /** Pointer to the function call table of the interface.
    255260     *  As this is opaque this must be casted to the right interface
    256261     *  struct defined below based on the interface type in enmInterface. */
     
    288293        AssertMsgBreak(pVDIfs->cbSize == sizeof(VDINTERFACE),
    289294                       ("cbSize=%u\n", pVDIfs->cbSize));
    290                        
     295
    291296        if (pVDIfs->enmInterface == enmInterface)
    292297            return pVDIfs;
     
    395400}
    396401
    397 /** 
     402/**
    398403 * Completion callback which is called by the interface owner
    399404 * to inform the backend that a task finished.
     
    455460     * @param   pcbWritten      Where to store how many bytes where actually written.
    456461     */
    457     DECLR3CALLBACKMEMBER(int, pfnWrite, (void *pvUser, void *pStorage, uint64_t uOffset, 
     462    DECLR3CALLBACKMEMBER(int, pfnWrite, (void *pvUser, void *pStorage, uint64_t uOffset,
    458463                                         size_t cbWrite, const void *pvBuf, size_t *pcbWritten));
    459464
     
    469474     * @param   pcbRead         Where to store how many bytes where actually read.
    470475     */
    471     DECLR3CALLBACKMEMBER(int, pfnRead, (void *pvUser, void *pStorage, uint64_t uOffset, 
     476    DECLR3CALLBACKMEMBER(int, pfnRead, (void *pvUser, void *pStorage, uint64_t uOffset,
    472477                                        size_t cbRead, void *pvBuf, size_t *pcbRead));
    473478
     
    492497     * @param   ppTask         Where to store the opaque task handle.
    493498     */
    494     DECLR3CALLBACKMEMBER(int, pfnPrepareRead, (void *pvUser, void *pStorage, uint64_t uOffset, 
     499    DECLR3CALLBACKMEMBER(int, pfnPrepareRead, (void *pvUser, void *pStorage, uint64_t uOffset,
    495500                                               void *pvBuf, size_t cbRead, void **ppTask));
    496501
     
    506511     * @param   ppTask         Where to store the opaque task handle.
    507512     */
    508     DECLR3CALLBACKMEMBER(int, pfnPrepareWrite, (void *pvUser, void *pStorage, uint64_t uOffset, 
     513    DECLR3CALLBACKMEMBER(int, pfnPrepareWrite, (void *pvUser, void *pStorage, uint64_t uOffset,
    509514                                                void *pvBuf, size_t cbWrite, void **ppTask));
    510515
     
    550555/**
    551556 * Progress notification interface
    552  * 
     557 *
    553558 * Per-operation. Optional.
    554559 */
     
    687692DECLINLINE(PVDINTERFACECONFIG) VDGetInterfaceConfig(PVDINTERFACE pInterface)
    688693{
    689     /* Check that the interface descriptor is a progress interface. */
     694    /* Check that the interface descriptor is a config interface. */
    690695    AssertMsgReturn(   (pInterface->enmInterface == VDINTERFACETYPE_CONFIG)
    691696                    && (pInterface->cbSize == sizeof(VDINTERFACE)),
     
    705710 * Query configuration, validates that the values are within a set of valid names.
    706711 *
    707  * @returns true if all names are found in pszzAllowed.
    708  * @returns false if not.
     712 * @return  true if all names are found in pszzAllowed.
     713 * @return  false if not.
    709714 * @param   pCfgIf      Pointer to configuration callback table.
    710715 * @param   pNode       The node which values should be examined.
     
    721726/**
    722727 * Query configuration, unsigned 64-bit integer value with default.
    723  * 
     728 *
    724729 * @return  VBox status code.
    725730 * @param   pCfgIf      Pointer to configuration callback table.
     
    738743/**
    739744 * Query configuration, unsigned 32-bit integer value with default.
    740  * 
     745 *
    741746 * @return  VBox status code.
    742747 * @param   pCfgIf      Pointer to configuration callback table.
     
    764769/**
    765770 * Query configuration, bool value with default.
    766  * 
     771 *
    767772 * @return  VBox status code.
    768773 * @param   pCfgIf      Pointer to configuration callback table.
     
    786791 * Query configuration, dynamically allocated (RTMemAlloc) zero terminated
    787792 * character value.
    788  * 
     793 *
    789794 * @return  VBox status code.
    790795 * @param   pCfgIf      Pointer to configuration callback table.
     
    821826 * Query configuration, dynamically allocated (RTMemAlloc) zero terminated
    822827 * character value with default.
    823  * 
     828 *
    824829 * @return  VBox status code.
    825830 * @param   pCfgIf      Pointer to configuration callback table.
     
    862867/**
    863868 * Query configuration, dynamically allocated (RTMemAlloc) byte string value.
    864  * 
     869 *
    865870 * @return  VBox status code.
    866871 * @param   pCfgIf      Pointer to configuration callback table.
     
    898903
    899904
     905/**
     906 * TCP network stack interface
     907 *
     908 * Per-disk. Mandatory for backends which have the VD_CAP_TCPNET bit set.
     909 */
     910typedef struct VDINTERFACETCPNET
     911{
     912    /**
     913     * Size of the configuration interface.
     914     */
     915    uint32_t    cbSize;
     916
     917    /**
     918     * Interface type.
     919     */
     920    VDINTERFACETYPE enmInterface;
     921
     922    /**
     923     * Connect as a client to a TCP port.
     924     *
     925     * @return  iprt status code.
     926     * @param   pszAddress      The address to connect to.
     927     * @param   uPort           The port to connect to.
     928     * @param   pSock           Where to store the handle to the established connect
     929ion.
     930     */
     931    DECLR3CALLBACKMEMBER(int, pfnClientConnect, (const char *pszAddress, uint32_t uPort, PRTSOCKET pSock));
     932
     933    /**
     934     * Close a TCP connection.
     935     *
     936     * @return  iprt status code.
     937     * @param   Sock            Socket descriptor.
     938ion.
     939     */
     940    DECLR3CALLBACKMEMBER(int, pfnClientClose, (RTSOCKET Sock));
     941
     942    /**
     943     * Socket I/O multiplexing.
     944     * Checks if the socket is ready for reading.
     945     *
     946     * @return  iprt status code.
     947     * @param   Sock        Socket descriptor.
     948     * @param   cMillies    Number of milliseconds to wait for the socket.
     949     *                      Use RT_INDEFINITE_WAIT to wait for ever.
     950     */
     951    DECLR3CALLBACKMEMBER(int, pfnSelectOne, (RTSOCKET Sock, unsigned cMillies));
     952
     953    /**
     954     * Receive data from a socket.
     955     *
     956     * @return  iprt status code.
     957     * @param   Sock        Socket descriptor.
     958     * @param   pvBuffer    Where to put the data we read.
     959     * @param   cbBuffer    Read buffer size.
     960     * @param   pcbRead     Number of bytes read.
     961     *                      If NULL the entire buffer will be filled upon successful return.
     962     *                      If not NULL a partial read can be done successfully.
     963     */
     964    DECLR3CALLBACKMEMBER(int, pfnRead, (RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead));
     965
     966    /**
     967     * Send data from a socket.
     968     *
     969     * @return  iprt status code.
     970     * @param   Sock        Socket descriptor.
     971     * @param   pvBuffer    Buffer to write data to socket.
     972     * @param   cbBuffer    How much to write.
     973     * @param   pcbRead     Number of bytes read.
     974     */
     975    DECLR3CALLBACKMEMBER(int, pfnWrite, (RTSOCKET Sock, const void *pvBuffer, size_t cbBuffer));
     976
     977    /**
     978     * Flush socket write buffers.
     979     *
     980     * @return  iprt status code.
     981     * @param   Sock        Socket descriptor.
     982     */
     983    DECLR3CALLBACKMEMBER(int, pfnFlush, (RTSOCKET Sock));
     984
     985} VDINTERFACETCPNET, *PVDINTERFACETCPNET;
     986
     987/**
     988 * Get TCP network stack interface from opaque callback table.
     989 *
     990 * @return Pointer to the callback table.
     991 * @param  pInterface Pointer to the interface descriptor.
     992 */
     993DECLINLINE(PVDINTERFACETCPNET) VDGetInterfaceTcpNet(PVDINTERFACE pInterface)
     994{
     995    /* Check that the interface descriptor is a TCP network stack interface. */
     996    AssertMsgReturn(   (pInterface->enmInterface == VDINTERFACETYPE_TCPNET)
     997                    && (pInterface->cbSize == sizeof(VDINTERFACE)),
     998                    ("Not a TCP network stack interface"), NULL);
     999
     1000    PVDINTERFACETCPNET pInterfaceTcpNet = (PVDINTERFACETCPNET)pInterface->pCallbacks;
     1001
     1002    /* Do basic checks. */
     1003    AssertMsgReturn(   (pInterfaceTcpNet->cbSize == sizeof(VDINTERFACETCPNET))
     1004                    && (pInterfaceTcpNet->enmInterface == VDINTERFACETYPE_TCPNET),
     1005                    ("A non TCP network stack callback table attached to a TCP network stack interface descriptor\n"), NULL);
     1006
     1007    return pInterfaceTcpNet;
     1008}
     1009
     1010
    9001011/** @name Configuration interface key handling flags.
    9011012 * @{
     
    14951606 * @param   pvUser          User data which is passed on completion
    14961607 */
    1497 VBOXDDU_DECL(int) VDAsyncRead(PVBOXHDD pDisk, uint64_t uOffset, size_t cbRead, 
     1608VBOXDDU_DECL(int) VDAsyncRead(PVBOXHDD pDisk, uint64_t uOffset, size_t cbRead,
    14981609                              PPDMDATASEG paSeg, unsigned cSeg,
    14991610                              void *pvUser);
  • trunk/src/VBox/Devices/Makefile.kmk

    r14448 r14526  
    819819    Storage/ISCSIHDDCore.cpp
    820820 VBoxDDU_DEFS         += VBOX_WITH_ISCSI
     821 Storage/DrvVD.cpp_INCS = \
     822        Network/lwip/src/include \
     823        Network/lwip/src/include/ipv4 \
     824        Network/lwip/vbox/include
    821825endif # VBOX_WITH_ISCSI
    822826
  • trunk/src/VBox/Devices/Storage/DrvVD.cpp

    r13840 r14526  
    3333#include <iprt/string.h>
    3434#include <iprt/cache.h>
     35#include <iprt/tcp.h>
     36
     37/* All lwip header files are not C++ safe. So hack around this. */
     38__BEGIN_DECLS
     39#include <lwip/inet.h>
     40#include <lwip/tcp.h>
     41#include <lwip/sockets.h>
     42__END_DECLS
    3543
    3644#include "Builtins.h"
     45
     46/* Small hack to get at lwIP initialized status */
     47extern bool DevINIPConfigured(void);
    3748
    3849
     
    107118    /** Callback table for error interface. */
    108119    VDINTERFACEERROR   VDIErrorCallbacks;
     120    /** Common structure for the supported TCP network stack interface. */
     121    VDINTERFACE        VDITcpNet;
     122    /** Callback table for TCP network stack interface. */
     123    VDINTERFACETCPNET  VDITcpNetCallbacks;
    109124    /** Common structure for the supported async I/O interface. */
    110125    VDINTERFACE        VDIAsyncIO;
     
    315330
    316331/*******************************************************************************
     332*   VD TCP network stack interface implementation - INIP case                  *
     333*******************************************************************************/
     334
     335/** @copydoc VDINTERFACETCPNET::pfnClientConnect */
     336static DECLCALLBACK(int) drvvdINIPClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock)
     337{
     338    int rc = VINF_SUCCESS;
     339    /* First check whether lwIP is set up in this VM instance. */
     340    if (!DevINIPConfigured())
     341    {
     342        LogRelFunc(("no IP stack\n"));
     343        return VERR_NET_HOST_UNREACHABLE;
     344    }
     345    /* Resolve hostname. As there is no standard resolver for lwIP yet,
     346     * just accept numeric IP addresses for now. */
     347    struct in_addr ip;
     348    if (!lwip_inet_aton(pszAddress, &ip))
     349    {
     350        LogRelFunc(("cannot resolve IP %s\n", pszAddress));
     351        return VERR_NET_HOST_UNREACHABLE;
     352    }
     353    /* Create socket and connect. */
     354    RTSOCKET Sock = lwip_socket(PF_INET, SOCK_STREAM, 0);
     355    if (Sock != -1)
     356    {
     357        struct sockaddr_in InAddr = {0};
     358        InAddr.sin_family = AF_INET;
     359        InAddr.sin_port = htons(uPort);
     360        InAddr.sin_addr = ip;
     361        if (!lwip_connect(Sock, (struct sockaddr *)&InAddr, sizeof(InAddr)))
     362        {
     363            *pSock = Sock;
     364            return VINF_SUCCESS;
     365        }
     366        rc = VERR_NET_CONNECTION_REFUSED; /* @todo real solution needed */
     367        lwip_close(Sock);
     368    }
     369    else
     370        rc = VERR_NET_CONNECTION_REFUSED; /* @todo real solution needed */
     371    return rc;
     372}
     373
     374/** @copydoc VDINTERFACETCPNET::pfnClientClose */
     375static DECLCALLBACK(int) drvvdINIPClientClose(RTSOCKET Sock)
     376{
     377    lwip_close(Sock);
     378    return VINF_SUCCESS; /** @todo real solution needed */
     379}
     380
     381/** @copydoc VDINTERFACETCPNET::pfnSelectOne */
     382static DECLCALLBACK(int) drvvdINIPSelectOne(RTSOCKET Sock, unsigned cMillies)
     383{
     384    fd_set fdsetR;
     385    FD_ZERO(&fdsetR);
     386    FD_SET(Sock, &fdsetR);
     387    fd_set fdsetE = fdsetR;
     388
     389    int rc;
     390    if (cMillies == RT_INDEFINITE_WAIT)
     391        rc = lwip_select(Sock + 1, &fdsetR, NULL, &fdsetE, NULL);
     392    else
     393    {
     394        struct timeval timeout;
     395        timeout.tv_sec = cMillies / 1000;
     396        timeout.tv_usec = (cMillies % 1000) * 1000;
     397        rc = lwip_select(Sock + 1, &fdsetR, NULL, &fdsetE, &timeout);
     398    }
     399    if (rc > 0)
     400        return VINF_SUCCESS;
     401    if (rc == 0)
     402        return VERR_TIMEOUT;
     403    return VERR_NET_CONNECTION_REFUSED; /** @todo real solution needed */
     404}
     405
     406/** @copydoc VDINTERFACETCPNET::pfnRead */
     407static DECLCALLBACK(int) drvvdINIPRead(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
     408{
     409    /* Do params checking */
     410    if (!pvBuffer || !cbBuffer)
     411    {
     412        AssertMsgFailed(("Invalid params\n"));
     413        return VERR_INVALID_PARAMETER;
     414    }
     415
     416    /*
     417     * Read loop.
     418     * If pcbRead is NULL we have to fill the entire buffer!
     419     */
     420    size_t cbRead = 0;
     421    size_t cbToRead = cbBuffer;
     422    for (;;)
     423    {
     424        /** @todo this clipping here is just in case (the send function
     425         * needed it, so I added it here, too). Didn't investigate if this
     426         * really has issues. Better be safe than sorry. */
     427        ssize_t cbBytesRead = lwip_recv(Sock, (char *)pvBuffer + cbRead,
     428                                        RT_MIN(cbToRead, 32768), 0);
     429        if (cbBytesRead < 0)
     430            return VERR_NET_CONNECTION_REFUSED; /** @todo real solution */
     431        if (cbBytesRead == 0 && errno)
     432            return VERR_NET_CONNECTION_REFUSED; /** @todo real solution */
     433        if (pcbRead)
     434        {
     435            /* return partial data */
     436            *pcbRead = cbBytesRead;
     437            break;
     438        }
     439
     440        /* read more? */
     441        cbRead += cbBytesRead;
     442        if (cbRead == cbBuffer)
     443            break;
     444
     445        /* next */
     446        cbToRead = cbBuffer - cbRead;
     447    }
     448
     449    return VINF_SUCCESS;
     450}
     451
     452/** @copydoc VDINTERFACETCPNET::pfnWrite */
     453static DECLCALLBACK(int) drvvdINIPWrite(RTSOCKET Sock, const void *pvBuffer, size_t cbBuffer)
     454{
     455    do
     456    {
     457        /** @todo lwip send only supports up to 65535 bytes in a single
     458         * send (stupid limitation buried in the code), so make sure we
     459         * don't get any wraparounds. This should be moved to DevINIP
     460         * stack interface once that's implemented. */
     461        ssize_t cbWritten = lwip_send(Sock, (void *)pvBuffer,
     462                                      RT_MIN(cbBuffer, 32768), 0);
     463        if (cbWritten < 0)
     464            return VERR_NET_CONNECTION_REFUSED; /** @todo real solution needed */
     465        AssertMsg(cbBuffer >= (size_t)cbWritten, ("Wrote more than we requested!!! cbWritten=%d cbBuffer=%d\n",
     466                                                  cbWritten, cbBuffer));
     467        cbBuffer -= cbWritten;
     468        pvBuffer = (const char *)pvBuffer + cbWritten;
     469    } while (cbBuffer);
     470
     471    return VINF_SUCCESS;
     472}
     473
     474/** @copydoc VDINTERFACETCPNET::pfnFlush */
     475static DECLCALLBACK(int) drvvdINIPFlush(RTSOCKET Sock)
     476{
     477    int fFlag = 1;
     478    lwip_setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY,
     479                    (const char *)&fFlag, sizeof(fFlag));
     480    fFlag = 0;
     481    lwip_setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY,
     482                    (const char *)&fFlag, sizeof(fFlag));
     483    return VINF_SUCCESS;
     484}
     485
     486
     487/*******************************************************************************
    317488*   Media interface methods                                                    *
    318489*******************************************************************************/
     
    629800
    630801    /*
    631      * Attach the async transport driver below of the device above us implements the
     802     * Attach the async transport driver below if the device above us implements the
    632803     * async interface.
    633804     */
     
    677848     * It's sort of up side down from the image dependency tree.
    678849     */
     850    bool        fHostIP = false;
    679851    unsigned    iLevel = 0;
    680852    PCFGMNODE   pCurNode = pCfgHandle;
     
    690862            fValid = CFGMR3AreValuesValid(pCurNode,
    691863                                          "Format\0Path\0"
    692                                           "ReadOnly\0HonorZeroWrites\0");
     864                                          "ReadOnly\0HonorZeroWrites\0"
     865                                          "HostIPStack\0");
     866
     867            rc = CFGMR3QueryBool(pCfgHandle, "HostIPStack", &fHostIP);
     868            if (rc == VERR_CFGM_VALUE_NOT_FOUND)
     869                fHostIP = true;
     870            else if (RT_FAILURE(rc))
     871            {
     872                rc = PDMDRV_SET_ERROR(pDrvIns, rc,
     873                                      N_("DrvVD: Configuration error: Querying \"HostIPStack\" as boolean failed"));
     874                break;
     875            }
    693876        }
    694877        else
     
    717900    if (RT_SUCCESS(rc))
    718901    {
     902        /* First of all figure out what kind of TCP networking stack interface
     903         * to use. This is done unconditionally, as backends which don't need
     904         * it will just ignore it. */
     905        if (fHostIP)
     906        {
     907            pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
     908            pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
     909            pThis->VDITcpNetCallbacks.pfnClientConnect = RTTcpClientConnect;
     910            pThis->VDITcpNetCallbacks.pfnClientClose = RTTcpClientClose;
     911            pThis->VDITcpNetCallbacks.pfnSelectOne = RTTcpSelectOne;
     912            pThis->VDITcpNetCallbacks.pfnRead = RTTcpRead;
     913            pThis->VDITcpNetCallbacks.pfnWrite = RTTcpWrite;
     914            pThis->VDITcpNetCallbacks.pfnFlush = RTTcpFlush;
     915        }
     916        else
     917        {
     918            pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
     919            pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
     920            pThis->VDITcpNetCallbacks.pfnClientConnect = drvvdINIPClientConnect;
     921            pThis->VDITcpNetCallbacks.pfnClientClose = drvvdINIPClientClose;
     922            pThis->VDITcpNetCallbacks.pfnSelectOne = drvvdINIPSelectOne;
     923            pThis->VDITcpNetCallbacks.pfnRead = drvvdINIPRead;
     924            pThis->VDITcpNetCallbacks.pfnWrite = drvvdINIPWrite;
     925            pThis->VDITcpNetCallbacks.pfnFlush = drvvdINIPFlush;
     926        }
     927        rc = VDInterfaceAdd(&pThis->VDITcpNet, "DrvVD_INIP",
     928                            VDINTERFACETYPE_TCPNET,
     929                            &pThis->VDITcpNetCallbacks, NULL,
     930                            &pThis->pVDIfsDisk);
     931        AssertRC(rc);
     932
    719933        rc = VDCreate(pThis->pVDIfsDisk, &pThis->pDisk);
    720934        /* Error message is already set correctly. */
Note: See TracChangeset for help on using the changeset viewer.

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