VirtualBox

Changeset 2382 in vbox for trunk/src/VBox/Main


Ignore:
Timestamp:
Apr 27, 2007 7:50:36 AM (18 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
20786
Message:

New dynamic TAP setup code for Linux

Location:
trunk/src/VBox/Main
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/ConsoleImpl.cpp

    r2358 r2382  
    2626#   include <sys/poll.h>
    2727#   include <sys/fcntl.h>
     28#   include <sys/types.h>
     29#   include <sys/wait.h>
    2830#   include <net/if.h>
    2931#   include <linux/if_tun.h>
     32#   include <stdio.h>
     33#   include <stdlib.h>
     34#   include <string.h>
    3035#endif
    3136
     
    55585563
    55595564/**
     5565  * Call the initialisation script for a dynamic TAP interface.
     5566  *
     5567  * The initialisation script should create a TAP interface, set it up and write its name to
     5568  * standard output followed by a carriage return.  Anything further written to standard
     5569  * output will be ignored.  If it returns a non-zero exit code, or does not write an
     5570  * intelligable interface name to standard output, it will be treated as having failed.
     5571  * For now, this method only works on Linux.
     5572  *
     5573  * @returns COM status code
     5574  * @param   tapDevice           string to store the name of the tap device created to
     5575  * @param   tapSetupApplication the name of the setup script
     5576  */
     5577HRESULT Console::callTapSetupApplication(Bstr &tapDevice, Bstr &tapSetupApplication)
     5578{
     5579    LogFlowThisFunc(("\n"));
     5580#ifdef __LINUX__
     5581    /* Command line to start the script with. */
     5582    const char *pszArgs;
     5583    /* Buffer to read the script output to.  It doesn't have to be long, as we are only
     5584        interested in the first few (normally 5 or 6) bytes. */
     5585    char acBuffer[64];
     5586    /* The size of the string returned by the script.  We only accept strings of 63 characters
     5587       or less. */
     5588    size_t cBufSize;
     5589    /* Result code */
     5590    int rc;
     5591
     5592    /* Get the script name. */
     5593    Utf8Str tapSetupApp(tapSetupApplication);
     5594    pszArgs = tapSetupApp.raw();
     5595    /*
     5596     * Create the process and read its output.
     5597     */
     5598    FILE *pfScriptHandle = popen(pszArgs, "r");
     5599    if (pfScriptHandle == 0)
     5600    {
     5601        int iErr = errno;
     5602        Log(("Failed to start the TAP interface setup script %s, error text: %s\n",
     5603              pszArgs, strerror(iErr)));
     5604        LogFlowThisFunc(("rc=E_FAIL\n"));
     5605        return setError(E_FAIL, "Failed to start the TAP interface setup script %s, error text: %s\n",
     5606                        pszArgs, strerror(iErr));
     5607    }
     5608    fgets(acBuffer, sizeof(acBuffer), pfScriptHandle);
     5609    cBufSize = strlen(acBuffer);
     5610    /* The script must return the name of the interface followed by a carriage return as the
     5611       first line of its output.  We need a null-terminated string. */
     5612    if ((cBufSize < 2) || (acBuffer[cBufSize - 1] != '\n'))
     5613    {
     5614        pclose(pfScriptHandle);
     5615        Log(("The TAP interface setup script did not return the name of a TAP device.\n"));
     5616        LogFlowThisFunc(("rc=E_FAIL\n"));
     5617        return setError(E_FAIL, "The TAP interface setup script did not return the name of a TAP device.\n");
     5618    }
     5619    acBuffer[cBufSize - 1] = 0;
     5620    tapDevice = acBuffer;
     5621    rc = pclose(pfScriptHandle);
     5622    if (!WIFEXITED(rc))
     5623    {
     5624        Log(("The TAP interface setup script terminated abnormally.\n"));
     5625        LogFlowThisFunc(("rc=E_FAIL\n"));
     5626        return setError(E_FAIL, "The TAP interface setup script terminated abnormally.\n");
     5627    }
     5628    if (WEXITSTATUS(rc) != 0)
     5629    {
     5630        Log(("The TAP interface setup script returned a non-zero exit code.\n"));
     5631        LogFlowThisFunc(("rc=E_FAIL\n"));
     5632        return setError(E_FAIL, "The TAP interface setup script returned a non-zero exit code.\n");
     5633    }
     5634    LogFlowThisFunc(("rc=S_OK\n"));
     5635    return S_OK;
     5636#else /* __LINUX__ not defined */
     5637    LogFlowThisFunc(("rc=E_NOTIMPL\n"));
     5638    return E_NOTIMPL;  /* not yet supported */
     5639#endif
     5640}
     5641
     5642/**
    55605643 *  Helper function to handle host interface device creation and attachment.
    55615644 *
     
    55675650HRESULT Console::attachToHostInterface(INetworkAdapter *networkAdapter)
    55685651{
     5652    LogFlowThisFunc(("\n"));
    55695653    /* sanity check */
    55705654    AssertReturn (isLockedOnCurrentThread(), E_FAIL);
     
    56235707            struct ifreq IfReq;
    56245708            memset(&IfReq, 0, sizeof(IfReq));
    5625             Bstr tapDeviceName;
     5709            /* The name of the TAP interface we are using and the TAP setup script resp. */
     5710            Bstr tapDeviceName, tapSetupApplication;
    56265711            rc = networkAdapter->COMGETTER(HostInterface)(tapDeviceName.asOutParam());
    56275712            if (FAILED(rc) || tapDeviceName.isEmpty())
    5628                 strcpy(IfReq.ifr_name, "tap%d");
    5629             else
     5713            {
     5714                networkAdapter->COMGETTER(TAPSetupApplication)(tapSetupApplication.asOutParam());
     5715                if (tapSetupApplication.isEmpty())
     5716                {
     5717                    Log(("No setup application was supplied for the TAP interface.\n"));
     5718                    rc = setError(E_FAIL, "No setup application was supplied for the TAP interface.\n");
     5719                }
     5720                else
     5721                {
     5722                    rc = callTapSetupApplication(tapDeviceName, tapSetupApplication);
     5723                }
     5724            }
     5725            if (SUCCEEDED(rc))
    56305726            {
    56315727                Utf8Str str(tapDeviceName);
     
    56345730                else
    56355731                    memcpy(IfReq.ifr_name, str.raw(), sizeof(IfReq.ifr_name) - 1); /** @todo bitch about names which are too long... */
    5636             }
    5637             IfReq.ifr_flags = IFF_TAP | IFF_NO_PI;
    5638             rcVBox = ioctl(maTapFD[slot], TUNSETIFF, &IfReq);
    5639             if (!rcVBox)
    5640             {
    5641                 /*
    5642                  * Make it pollable.
    5643                  */
    5644                 if (fcntl(maTapFD[slot], F_SETFL, O_NONBLOCK) != -1)
     5732                IfReq.ifr_flags = IFF_TAP | IFF_NO_PI;
     5733                rcVBox = ioctl(maTapFD[slot], TUNSETIFF, &IfReq);
     5734                if (!rcVBox)
    56455735                {
    5646                     tapDeviceName = IfReq.ifr_name;
    5647                     if (tapDeviceName)
     5736                    /*
     5737                    * Make it pollable.
     5738                    */
     5739                    if (fcntl(maTapFD[slot], F_SETFL, O_NONBLOCK) != -1)
    56485740                    {
    5649                         Log(("attachToHostInterface: %RTfile %ls\n", maTapFD[slot], tapDeviceName.raw()));
    5650 
    5651                         /*
    5652                          * Here is the right place to communicate the TAP file descriptor and
    5653                          * the host interface name to the server if/when it becomes really
    5654                          * necessary.
    5655                          */
    5656                         maTAPDeviceName[slot] = tapDeviceName;
    5657                         rcVBox = VINF_SUCCESS;
    5658                         rc = S_OK;
     5741                        tapDeviceName = IfReq.ifr_name;
     5742                        if (tapDeviceName)
     5743                        {
     5744                            Log(("attachToHostInterface: %RTfile %ls\n", maTapFD[slot], tapDeviceName.raw()));
     5745   
     5746                            /*
     5747                            * Here is the right place to communicate the TAP file descriptor and
     5748                            * the host interface name to the server if/when it becomes really
     5749                            * necessary.
     5750                            */
     5751                            maTAPDeviceName[slot] = tapDeviceName;
     5752                            rcVBox = VINF_SUCCESS;
     5753                            rc = S_OK;
     5754                        }
     5755                        else
     5756                            rcVBox = VERR_NO_MEMORY;
    56595757                    }
    56605758                    else
    5661                         rcVBox = VERR_NO_MEMORY;
     5759                    {
     5760                        AssertMsgFailed(("Configuration error: Failed to configure /dev/net/tun non blocking. errno=%d\n", errno));
     5761                        rcVBox = VERR_HOSTIF_BLOCKING;
     5762                        rc = setError(E_FAIL, "Failed to set /dev/net/tun to non blocking. errno=%d\n", errno);
     5763                    }
    56625764                }
    56635765                else
    56645766                {
    5665                     AssertMsgFailed(("Configuration error: Failed to configure /dev/net/tun non blocking. errno=%d\n", errno));
    5666                     rcVBox = VERR_HOSTIF_BLOCKING;
    5667                     rc = setError(E_FAIL, "Failed to set /dev/net/tun to non blocking. errno=%d\n", errno);
     5767                    AssertMsgFailed(("Configuration error: Failed to configure /dev/net/tun. errno=%d\n", errno));
     5768                    rcVBox = VERR_HOSTIF_IOCTL;
     5769                    rc = setError(E_FAIL, "Failed to configure /dev/net/tun. errno = %d\n", errno);
    56685770                }
    5669             }
    5670             else
    5671             {
    5672                 AssertMsgFailed(("Configuration error: Failed to configure /dev/net/tun. errno=%d\n", errno));
    5673                 rcVBox = VERR_HOSTIF_IOCTL;
    5674                 rc = setError(E_FAIL, "Failed to configure /dev/net/tun. errno = %d\n", errno);
    56755771            }
    56765772        }
     
    57035799        }
    57045800    }
    5705 #ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
    5706     if (SUCCEEDED(rc))
    5707     {
    5708         /*
    5709          * Call the initialization program.
    5710          *
    5711          * The initialization program is passed the device name as the first param.
    5712          * The second parameter is the decimal value of the file handle of the device
    5713          * which it inherits.
    5714          */
    5715         Bstr tapSetupApplication;
    5716         networkAdapter->COMGETTER(TAPSetupApplication)(tapSetupApplication.asOutParam());
    5717         if (tapSetupApplication)
    5718         {
    5719             /*
    5720              * Create the argument list.
    5721              */
    5722             const char *apszArgs[4];
    5723             /* 0. The program name. */
    5724             Utf8Str tapSetupApp(tapSetupApplication);
    5725             apszArgs[0] = tapSetupApp.raw();
    5726 
    5727             /* 1. The file descriptor. */
    5728             char szFD[32];
    5729             RTStrPrintf(szFD, sizeof(szFD), "%RTfile", maTapFD[slot]);
    5730             apszArgs[1] = szFD;
    5731 
    5732             /* 2. The device name (optional). */
    5733             apszArgs[2] = maTAPDeviceName[slot].isEmpty() ? NULL : maTAPDeviceName[slot].raw();
    5734 
    5735             /* 3. The end. */
    5736             apszArgs[3] = NULL;
    5737 
    5738             /*
    5739              * Create the process and wait for it to complete.
    5740              */
    5741             RTPROCESS Process;
    5742             int rcVBox = RTProcCreate(apszArgs[0], &apszArgs[0], NULL, 0, &Process);
    5743             if (VBOX_SUCCESS(rcVBox))
    5744             {
    5745                 /* wait for the process to exit */
    5746                 RTPROCSTATUS ProcStatus;
    5747                 rcVBox = RTProcWait(Process, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus);
    5748                 AssertRC(rcVBox);
    5749                 if (VBOX_SUCCESS(rcVBox))
    5750                 {
    5751                     if (    ProcStatus.enmReason == RTPROCEXITREASON_NORMAL
    5752                         &&  ProcStatus.iStatus == 0)
    5753                         rcVBox = VINF_SUCCESS;
    5754                     else
    5755                         rcVBox = VMSetError(mpVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_("Failed to initialize Host Interface Networking"));
    5756                 }
    5757             }
    5758             else
    5759             {
    5760                 AssertMsgFailed(("Configuration error: Failed to start init program \"%s\", rc=%Vra\n", tapSetupApp.raw(), rcVBox));
    5761                 rc = setError(E_FAIL, "Failed to start init program \"%s\", rc = %Vra\n", tapSetupApp.raw(), rcVBox);
    5762             }
    5763 
    5764             /* in case of failure, cleanup. */
    5765             if (VBOX_FAILURE(rcVBox) && SUCCEEDED(rc))
    5766             {
    5767                 rc = setError(E_FAIL, tr ("General failure configuring Host Interface Networking"));
    5768             }
    5769         }
    5770     }
    5771 #endif /* VBOX_WITH_UNIXY_TAP_NETWORKING */
     5801    LogFlowThisFunc(("rc=%d\n", rc));
    57725802    return rc;
    57735803}
    57745804
    5775 /**
    5776  *  Helper function to handle detachment from a host interface
    5777  *
    5778  *  @param   networkAdapter the network adapter which attachment should be reset
    5779  *  @return  COM status code
    5780  *
    5781  *  @note The caller must lock this object for writing.
    5782  */
     5805#if 0
     5806/* Old code for this function. */
    57835807HRESULT Console::detachFromHostInterface(INetworkAdapter *networkAdapter)
    57845808{
     
    58585882    }
    58595883#endif
     5884    return rc;
     5885}
     5886#endif
     5887
     5888/**
     5889 *  Helper function to handle detachment from a host interface
     5890 *
     5891 *  @param   networkAdapter the network adapter which attachment should be reset
     5892 *  @return  COM status code
     5893 *
     5894 *  @note The caller must lock this object for writing.
     5895 */
     5896HRESULT Console::detachFromHostInterface(INetworkAdapter *networkAdapter)
     5897{
     5898    /* sanity check */
     5899    LogFlowThisFunc(("\n"));
     5900    AssertReturn (isLockedOnCurrentThread(), E_FAIL);
     5901
     5902    HRESULT rc = S_OK;
     5903#ifdef DEBUG
     5904    /* paranoia */
     5905    NetworkAttachmentType_T attachment;
     5906    networkAdapter->COMGETTER(AttachmentType)(&attachment);
     5907    Assert(attachment == NetworkAttachmentType_HostInterfaceNetworkAttachment);
     5908#endif /* DEBUG */
     5909
     5910#ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
     5911
     5912    ULONG slot = 0;
     5913    rc = networkAdapter->COMGETTER(Slot)(&slot);
     5914    AssertComRC(rc);
     5915
     5916    /* is there an open TAP device? */
     5917    if (maTapFD[slot] != NIL_RTFILE)
     5918    {
     5919        /*
     5920         * Close the file handle.
     5921         */
     5922        int rcVBox = RTFileClose(maTapFD[slot]);
     5923        AssertRC(rcVBox);
     5924        /*
     5925         * Execute the termination command.
     5926         */
     5927        Bstr tapTerminateApplication;
     5928        networkAdapter->COMGETTER(TAPTerminateApplication)(tapTerminateApplication.asOutParam());
     5929        if (tapTerminateApplication)
     5930        {
     5931            /* Get the program name. */
     5932            Utf8Str tapTermAppUtf8(tapTerminateApplication);
     5933
     5934            /* Build the command line. */
     5935            char szCommand[4096];
     5936            RTStrPrintf(szCommand, sizeof(szCommand), "%s %RTfile %s", tapTermAppUtf8.raw(),
     5937                        maTapFD[slot],
     5938                        maTAPDeviceName[slot].isEmpty() ? "" : maTAPDeviceName[slot].raw());
     5939
     5940            /*
     5941             * Create the process and wait for it to complete.
     5942             */
     5943            Log(("Calling the termination command: %s\n", szCommand));
     5944            int rcCommand = system(szCommand);
     5945            if (rcCommand == -1)
     5946            {
     5947                Log(("Failed to execute the clean up script for the TAP interface"));
     5948                rc = setError(E_FAIL, tr ("Failed to execute the clean up script for the TAP interface"));
     5949            }
     5950            if (!WIFEXITED(rc))
     5951            {
     5952                Log(("The TAP interface clean up script terminated abnormally.\n"));
     5953                rc = setError(E_FAIL, "The TAP interface clean up script terminated abnormally.\n");
     5954            }
     5955            if (WEXITSTATUS(rc) != 0)
     5956            {
     5957                Log(("The TAP interface clean up script returned a non-zero exit code.\n"));
     5958                rc = setError(E_FAIL, "The TAP interface clean up script returned a non-zero exit code.\n");
     5959            }
     5960        }
     5961
     5962        /* the TAP device name and handle are no longer valid */
     5963        maTapFD[slot] = NIL_RTFILE;
     5964        maTAPDeviceName[slot] = "";
     5965    }
     5966#endif
     5967    LogFlowThisFunc(("returning %d\n", rc));
    58605968    return rc;
    58615969}
  • trunk/src/VBox/Main/include/ConsoleImpl.h

    r2333 r2382  
    340340    HRESULT powerDown();
    341341
     342    HRESULT callTapSetupApplication(Bstr &tapDevice, Bstr &tapSetupApplication);
    342343    HRESULT attachToHostInterface(INetworkAdapter *networkAdapter);
    343344    HRESULT detachFromHostInterface(INetworkAdapter *networkAdapter);
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