VBoxNetFlt.c revision de4157257515400c2c25373591135f110227b68c
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * VBoxNetFlt - Network Filter Driver (Host), Common Code.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * Copyright (C) 2008 Sun Microsystems, Inc.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * available from http://www.virtualbox.org. This file is free software;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * you can redistribute it and/or modify it under the terms of the GNU
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * General Public License (GPL) as published by the Free Software
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * additional information or have any questions.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync/** @page pg_netflt VBoxNetFlt - Network Interface Filter
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * This is a kernel module that attaches to a real interface on the host
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * and filters and injects packets.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * In the big picture we're one of the three trunk interface on the internal
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * network, the one named "NIC Filter Driver": @image html Networking_Overview.gif
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * @section sec_netflt_msc Locking / Sequence Diagrams
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * This secion contains a few sequence diagrams describing the problematic
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * transitions of a host interface filter instance.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * The thing that makes it all a bit problematic is that multiple events may
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * happen at the same time, and that we have to be very careful to avoid
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * deadlocks caused by mixing our locks with the ones in the host kernel.
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * The main events are receive, send, async send completion, disappearance of
6ffe15b8a1730e56a0a818da51c4e7a115da5763vboxsync * the host networking interface and it's reappearance. The latter two events
6ffe15b8a1730e56a0a818da51c4e7a115da5763vboxsync * are can be caused by driver unloading/loading or the device being physical
6ffe15b8a1730e56a0a818da51c4e7a115da5763vboxsync * unplugged (e.g. a USB network device).
6ffe15b8a1730e56a0a818da51c4e7a115da5763vboxsync * The strategy for dealing with these issues are:
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * - Use a simple state machine.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * - Require the user (IntNet) to serialize all its calls to us,
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * while at the same time not owning any lock used by any of the
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * the callbacks we might call on receive and async send completion.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * - Make sure we're 100% idle before disconnecting, and have a
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * disconnected status on both sides to fend off async calls.
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * - Protect the host specific interface handle and the state variables
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * using a spinlock.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * @subsection subsec_netflt_msc_dis_rel Disconnect from the network and release
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * VM, IntNet, NetFlt, Kernel, Wire;
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * VM->IntNet [label="pkt0", linecolor="green", textcolor="green"];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * IntNet=>IntNet [label="Lock Network", linecolor="green", textcolor="green" ];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * IntNet=>IntNet [label="Route packet -> wire", linecolor="green", textcolor="green" ];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * IntNet=>IntNet [label="Unlock Network", linecolor="green", textcolor="green" ];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * IntNet=>NetFlt [label="pkt0 to wire", linecolor="green", textcolor="green" ];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * NetFlt=>Kernel [label="pkt0 to wire", linecolor="green", textcolor="green"];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * Kernel->Wire [label="pkt0 to wire", linecolor="green", textcolor="green"];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * --- [label="Suspending the trunk interface"];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * IntNet=>IntNet [label="Lock Network"];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * Wire->Kernel [label="pkt1 - racing us", linecolor="red", textcolor="red"];
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync * Kernel=>>NetFlt [label="pkt1 - racing us", linecolor="red", textcolor="red"];
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync * NetFlt=>>IntNet [label="pkt1 recv - blocks", linecolor="red", textcolor="red"];
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync * IntNet=>IntNet [label="Mark Trunk Suspended"];
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync * IntNet=>IntNet [label="Unlock Network"];
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync * IntNet=>NetFlt [label="pfnSetActive(false)"];
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync * NetFlt=>NetFlt [label="Mark inactive (atomic)"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * IntNet<<NetFlt;
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * IntNet=>NetFlt [label="pfnWaitForIdle(forever)"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * IntNet=>>NetFlt [label="pkt1 to host", linecolor="red", textcolor="red"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * NetFlt=>>Kernel [label="pkt1 to host", linecolor="red", textcolor="red"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * Kernel<-Wire [label="pkt0 on wire", linecolor="green", textcolor="green"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * NetFlt<<Kernel [label="pkt0 on wire", linecolor="green", textcolor="green"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * IntNet<<=NetFlt [label="pfnSGRelease", linecolor="green", textcolor="green"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * IntNet<<=IntNet [label="Lock Net, free SG, Unlock Net", linecolor="green", textcolor="green"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * IntNet>>NetFlt [label="pfnSGRelease", linecolor="green", textcolor="green"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * NetFlt<-NetFlt [label="idle", linecolor="green", textcolor="green"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * IntNet<<NetFlt [label="idle (pfnWaitForIdle)"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * Wire->Kernel [label="pkt2", linecolor="red", textcolor="red"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * Kernel=>>NetFlt [label="pkt2", linecolor="red", textcolor="red"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * NetFlt=>>Kernel [label="pkt2 to host", linecolor="red", textcolor="red"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * VM->IntNet [label="pkt3", linecolor="green", textcolor="green"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * IntNet=>IntNet [label="Lock Network", linecolor="green", textcolor="green" ];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * IntNet=>IntNet [label="Route packet -> drop", linecolor="green", textcolor="green" ];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * IntNet=>IntNet [label="Unlock Network", linecolor="green", textcolor="green" ];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * --- [label="The trunk interface is idle now, disconnect it"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * IntNet=>IntNet [label="Lock Network"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * IntNet=>IntNet [label="Unlink Trunk"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * IntNet=>IntNet [label="Unlock Network"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * IntNet=>NetFlt [label="pfnDisconnectAndRelease"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * NetFlt=>Kernel [label="iflt_detach"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * NetFlt<<=Kernel [label="iff_detached"];
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * NetFlt>>Kernel [label="iff_detached"];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * NetFlt<<Kernel [label="iflt_detach"];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * NetFlt=>NetFlt [label="Release"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * IntNet<<NetFlt [label="pfnDisconnectAndRelease"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * @subsection subsec_netflt_msc_hif_rm Host Interface Removal
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * The ifnet_t (pIf) is a tricky customer as any reference to it can potentially
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * race the filter detaching. The simple way of solving it on Darwin is to guard
e0dec59adb362e8486c0622785420ad10e720972vboxsync * all access to the pIf member with a spinlock. The other host systems will
e0dec59adb362e8486c0622785420ad10e720972vboxsync * probably have similar race conditions, so the spinlock is a generic thing.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * VM, IntNet, NetFlt, Kernel;
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * VM->IntNet [label="pkt0", linecolor="green", textcolor="green"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * IntNet=>IntNet [label="Lock Network", linecolor="green", textcolor="green" ];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * IntNet=>IntNet [label="Route packet -> wire", linecolor="green", textcolor="green" ];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * IntNet=>IntNet [label="Unlock Network", linecolor="green", textcolor="green" ];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * IntNet=>NetFlt [label="pkt0 to wire", linecolor="green", textcolor="green" ];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * NetFlt=>Kernel [label="ifnet_reference w/ spinlock", linecolor="green", textcolor="green" ];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * NetFlt<<Kernel [label="ifnet_reference", linecolor="green", textcolor="green" ];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * NetFlt=>Kernel [label="pkt0 to wire (blocks)", linecolor="green", textcolor="green" ];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * --- [label="The host interface is being disconnected"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * Kernel->NetFlt [label="iff_detached"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * NetFlt=>Kernel [label="ifnet_release w/ spinlock"];
e0dec59adb362e8486c0622785420ad10e720972vboxsync * NetFlt<<Kernel [label="ifnet_release"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * NetFlt=>NetFlt [label="fDisconnectedFromHost=true"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * NetFlt>>Kernel [label="iff_detached"];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * NetFlt<<Kernel [label="dropped", linecolor="green", textcolor="green"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * NetFlt=>NetFlt [label="Acquire spinlock", linecolor="green", textcolor="green"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * NetFlt=>Kernel [label="ifnet_release", linecolor="green", textcolor="green"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * NetFlt<<Kernel [label="ifnet_release", linecolor="green", textcolor="green"];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * NetFlt=>NetFlt [label="pIf=NULL", linecolor="green", textcolor="green"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * NetFlt=>NetFlt [label="Release spinlock", linecolor="green", textcolor="green"];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * IntNet<=NetFlt [label="pfnSGRelease", linecolor="green", textcolor="green"];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * IntNet>>NetFlt [label="pfnSGRelease", linecolor="green", textcolor="green"];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * IntNet<<NetFlt [label="pkt0 to wire", linecolor="green", textcolor="green"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * @subsection subsec_netflt_msc_hif_rm Host Interface Rediscovery
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * The rediscovery is performed when we receive a send request and a certain
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * period have elapsed since the last attempt, i.e. we're polling it. We
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * synchronize the rediscovery with disconnection from the internal network
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * by means of the pfnWaitForIdle call, so no special handling is required.
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * VM2, VM1, IntNet, NetFlt, Kernel, Wire;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * --- [label="Rediscovery conditions are not met"];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * VM1->IntNet [label="pkt0"];
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * IntNet=>IntNet [label="Lock Network"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * IntNet=>IntNet [label="Route packet -> wire"];
e0dec59adb362e8486c0622785420ad10e720972vboxsync * IntNet=>IntNet [label="Unlock Network"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * IntNet=>NetFlt [label="pkt0 to wire"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * NetFlt=>NetFlt [label="Read pIf(==NULL) w/ spinlock"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * IntNet<<NetFlt [label="pkt0 to wire (dropped)"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * --- [label="Rediscovery conditions"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * VM1->IntNet [label="pkt1"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * IntNet=>IntNet [label="Lock Network"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * IntNet=>IntNet [label="Route packet -> wire"];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * IntNet=>IntNet [label="Unlock Network"];
* NetFlt=>NetFlt [label="!pIf || fRediscoveryPending (w/ spinlock)", linecolor="red", textcolor="red"];
#include "VBoxNetFltInternal.h"
#ifdef VBOXNETFLT_STATIC_CONFIG
static PVBOXNETFLTINS vboxNetFltFindInstanceLocked(PVBOXNETFLTGLOBALS pGlobals, const char *pszName)
return pCur;
return NULL;
return pRet;
bool fRediscovered;
bool fDoIt;
if (fDoIt)
if (fDoIt)
if (fRediscovered)
return fRediscovered;
static DECLCALLBACK(int) vboxNetFltPortXmit(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst)
int rc;
return rc;
int rc;
return rc;
return !fActive;
int rc;
#ifdef VBOXNETFLT_STATIC_CONFIG
if (fBusy)
if (!cRefs)
if (!cRefs)
if (fBusy)
static int vboxNetFltConnectIt(PVBOXNETFLTINS pThis, PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort)
int rc;
#ifdef VBOXNETFLT_STATIC_CONFIG
return rc;
static int vboxNetFltNewInstance(PVBOXNETFLTGLOBALS pGlobals, const char *pszName, PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort)
int rc;
if (!pNew)
return VERR_INTNET_FLT_IF_FAILED;
#ifdef VBOXNETFLT_STATIC_CONFIG
return rc;
return rc;
return rc;
static DECLCALLBACK(int) vboxNetFltFactoryCreateAndConnect(PINTNETTRUNKFACTORY pIfFactory, const char *pszName,
PVBOXNETFLTGLOBALS pGlobals = (PVBOXNETFLTGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETFLTGLOBALS, TrunkFactory));
int rc;
if (pCur)
#ifdef VBOXNETFLT_STATIC_CONFIG
return rc;
#ifdef VBOXNETFLT_STATIC_CONFIG
return rc;
PVBOXNETFLTGLOBALS pGlobals = (PVBOXNETFLTGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETFLTGLOBALS, TrunkFactory));
static DECLCALLBACK(void *) vboxNetFltQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)
PVBOXNETFLTGLOBALS pGlobals = (PVBOXNETFLTGLOBALS)((uint8_t *)pSupDrvFactory - RT_OFFSETOF(VBOXNETFLTGLOBALS, SupDrvFactory));
#ifdef LOG_ENABLED
return NULL;
return fRc;
int rc;
return VERR_WRONG_ORDER;
return VERR_WRONG_ORDER;
return VINF_SUCCESS;
rc = SUPR0IdcOpen(&pGlobals->SupDrvIDC, 0 /* iReqVersion = default */, 0 /* iMinVersion = default */, NULL, NULL, NULL);
return rc;
return rc;