1
0
mirror of https://git.FreeBSD.org/ports.git synced 2025-01-02 06:03:50 +00:00

- Improve error message if /usr/lib32 is not installed on amd64. [1]

- Fix pkg-plist. Additions directory is only created with
  WITH_GUESTADDITIONS option. [2]
- Add patch to fix panic with vboxnet driver. [3]
- Bump PORTREVISION.

PR:		ports/138935 [1] (based on)
Reported by:	scf@ [3]
Submitted by:	Julian H. Stacey <jhs AT berklix.com> [1],
		Bernhard Froehlich <decke AT bluelife.at> [2],
		Fredrik Lindberg <fli AT shapeshifter.se> [3]
On behalf of:	vbox@ (decke, dhn, itetcu, miwi, nox)
Feature safe:	yes
This commit is contained in:
Beat Gaetzi 2009-09-29 15:15:02 +00:00
parent 067cd70590
commit 972faa0f83
Notes: svn2git 2021-03-31 03:12:20 +00:00
svn path=/head/; revision=242234
20 changed files with 2070 additions and 20 deletions

View File

@ -7,6 +7,7 @@
PORTNAME= virtualbox
DISTVERSION= 3.0.51r22902
PORTREVISION= 1
CATEGORIES= emulators kld
MASTER_SITES= http://tmp.chruetertee.ch/ \
http://freebsd.unixfreunde.de/sources/ \
@ -142,15 +143,21 @@ BROKEN= Does not compile on FreeBSD 6.X
KMK_ARCH= freebsd.x86
PLIST_SUB+= I386=""
.else
.if !exists(/usr/lib32)
IGNORE= requires 32-bit libraries installed under /usr/lib32
.endif
KMK_ARCH= freebsd.${ARCH}
PLIST_SUB+= I386="@comment "
.endif
.include <bsd.port.pre.mk>
pre-everything::
.if ${ARCH} == "amd64"
.if !exists(/usr/lib32)
@${ECHO} 'Requires 32-bit libraries installed under /usr/lib32.'
@${ECHO} 'Do: cd /usr/src; make build32 install32; ldconfig -v -m -R /usr/lib32'
@${FALSE}
.endif
.endif
post-patch:
@${ECHO} 'VBOX_PATH_APP_PRIVATE_ARCH = ${PREFIX}/lib/virtualbox' > ${WRKSRC}/LocalConfig.kmk
@${ECHO} 'VBOX_PATH_SHARED_LIBS = ${PREFIX}/lib/virtualbox' >> ${WRKSRC}/LocalConfig.kmk

View File

@ -0,0 +1,28 @@
Index: src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h
===================================================================
--- src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h (revision 23391)
+++ src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h (working copy)
@@ -206,6 +206,14 @@
hook_p output;
/** Original interface flags */
unsigned int flags;
+ /** Input queue */
+ struct ifqueue inq;
+ /** Output queue */
+ struct ifqueue outq;
+ /** Input task */
+ struct task tskin;
+ /** Output task */
+ struct task tskout;
/** The MAC address of the interface. */
RTMAC Mac;
/** @} */
@@ -241,6 +249,8 @@
# endif
#elif defined(RT_OS_LINUX)
uint8_t abPadding[320];
+#elif defined(RT_OS_FREEBSD)
+ uint8_t abPadding[256];
#else
uint8_t abPadding[128];
#endif

View File

@ -0,0 +1,375 @@
Index: src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c
===================================================================
--- src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c (revision 23391)
+++ src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c (working copy)
@@ -43,6 +43,8 @@
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/syscallsubr.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
#include <net/if.h>
#include <net/if_var.h>
@@ -78,8 +80,6 @@
static ng_rcvdata_t ng_vboxnetflt_rcvdata;
static ng_disconnect_t ng_vboxnetflt_disconnect;
static int ng_vboxnetflt_mod_event(module_t mod, int event, void *data);
-static int ng_vboxnetflt_rcv_in(hook_p node, item_p item);
-static int ng_vboxnetflt_rcv_out(hook_p node, item_p item);
/** Netgraph node type */
#define NG_VBOXNETFLT_NODE_TYPE "vboxnetflt"
@@ -112,8 +112,8 @@
{
.version = NG_ABI_VERSION,
.name = NG_VBOXNETFLT_NODE_TYPE,
- .mod_event = vboxnetflt_modevent,
- .constructor = ng_vboxnetflt_constructor,
+ .mod_event = vboxnetflt_modevent,
+ .constructor = ng_vboxnetflt_constructor,
.rcvmsg = ng_vboxnetflt_rcvmsg,
.shutdown = ng_vboxnetflt_shutdown,
.newhook = ng_vboxnetflt_newhook,
@@ -267,16 +267,12 @@
if (strcmp(name, NG_VBOXNETFLT_HOOK_IN) == 0)
{
#if __FreeBSD_version >= 800000
- NG_HOOK_SET_RCVDATA(hook, ng_vboxnetflt_rcv_in);
NG_HOOK_SET_TO_INBOUND(hook);
#endif
pThis->u.s.input = hook;
}
else if (strcmp(name, NG_VBOXNETFLT_HOOK_OUT) == 0)
{
-#if __FreeBSD_version >= 800000
- NG_HOOK_SET_RCVDATA(hook, ng_vboxnetflt_rcv_out);
-#endif
pThis->u.s.output = hook;
}
else
@@ -310,161 +306,171 @@
/**
* Handle data on netgraph hooks.
+ * Frames processing is deferred to a taskqueue because this might
+ * be called with non-sleepable locks held and code paths inside
+ * the virtual switch might sleep.
*/
static int ng_vboxnetflt_rcvdata(hook_p hook, item_p item)
{
const node_p node = NG_HOOK_NODE(hook);
PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
+ struct ifnet *ifp = pThis->u.s.ifp;
struct mbuf *m;
+ struct m_tag *mtag;
+ bool fActive;
+ fActive = ASMAtomicUoReadBool(&pThis->fActive);
+
+ NGI_GET_M(item, m);
+ NG_FREE_ITEM(item);
+
+ /* Locate tag to see if processing should be skipped for this frame */
+ mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
+ if (mtag != NULL)
+ {
+ m_tag_unlink(m, mtag);
+ m_tag_free(mtag);
+ }
+
+ /*
+ * Handle incoming hook. This is connected to the
+ * input path of the interface, thus handling incoming frames.
+ */
if (pThis->u.s.input == hook)
- return ng_vboxnetflt_rcv_in(hook, item);
+ {
+ if (mtag != NULL || !fActive)
+ {
+ ether_demux(ifp, m);
+ return (0);
+ }
+ mtx_lock_spin(&pThis->u.s.inq.ifq_mtx);
+ _IF_ENQUEUE(&pThis->u.s.inq, m);
+ mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx);
+ taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskin);
+ }
+ /**
+ * Handle mbufs on the outgoing hook, frames going to the interface
+ */
else if (pThis->u.s.output == hook)
- return ng_vboxnetflt_rcv_out(hook, item);
+ {
+ if (mtag != NULL || !fActive)
+ return ether_output_frame(ifp, m);
+ mtx_lock_spin(&pThis->u.s.outq.ifq_mtx);
+ _IF_ENQUEUE(&pThis->u.s.outq, m);
+ mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx);
+ taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskout);
+ }
else
{
- NGI_GET_M(item, m);
- NG_FREE_ITEM(item);
+ m_freem(m);
}
return (0);
}
+static int ng_vboxnetflt_shutdown(node_p node)
+{
+ PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
+ bool fActive;
+
+ /* Prevent node shutdown if we're active */
+ fActive = ASMAtomicUoReadBool(&pThis->fActive);
+ if (fActive)
+ return (EBUSY);
+ NG_NODE_UNREF(node);
+ return (0);
+}
+
+static int ng_vboxnetflt_disconnect(hook_p hook)
+{
+ return (0);
+}
+
/**
- * Handle incoming hook. This is connected to the
- * input path of the interface, thus handling incoming frames.
+ * Input processing task, handles incoming frames
*/
-static int ng_vboxnetflt_rcv_in(hook_p hook, item_p item)
+static void vboxNetFltFreeBSDinput(void *arg, int pending)
{
+ PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg;
struct mbuf *m, *m0;
- struct m_tag *mtag;
- const node_p node = NG_HOOK_NODE(hook);
- PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
struct ifnet *ifp = pThis->u.s.ifp;
- bool fActive, fDropIt = false;
unsigned int cSegs = 0;
+ bool fDropIt = false, fActive;
PINTNETSG pSG;
- NGI_GET_M(item, m);
- NG_FREE_ITEM(item);
-
- fActive = ASMAtomicUoReadBool(&pThis->fActive);
- if (!fActive)
- goto out;
-
- mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
- if (mtag != NULL)
- {
- m_tag_unlink(m, mtag);
- m_tag_free(mtag);
- goto out;
- }
vboxNetFltRetain(pThis, true /* fBusy */);
-
- for (m0 = m; m0 != NULL; m0 = m0->m_next)
+ for (;;)
{
- if (m0->m_len > 0)
- cSegs++;
- }
+ mtx_lock_spin(&pThis->u.s.inq.ifq_mtx);
+ _IF_DEQUEUE(&pThis->u.s.inq, m);
+ mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx);
+ if (m == NULL)
+ break;
+ for (m0 = m; m0 != NULL; m0 = m0->m_next)
+ if (m0->m_len > 0)
+ cSegs++;
+
#ifdef PADD_RUNT_FRAMES_FROM_HOST
- if (m_length(m, NULL) < 60)
- cSegs++;
+ if (m_length(m, NULL) < 60)
+ cSegs++;
#endif
- /* Create a copy of the mbuf and hand it to the virtual switch */
- pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
- vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
- fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_WIRE);
- RTMemTmpFree(pSG);
+ /* Create a copy and deliver to the virtual switch */
+ pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
+ vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
+ fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
+ RTMemTmpFree(pSG);
+ if (fDropIt)
+ m_freem(m);
+ else
+ ether_demux(ifp, m);
+ }
vboxNetFltRelease(pThis, true /* fBusy */);
-
-out:
- /* Only deliver it to the host stack if the destination weren't a guest */
- if (fDropIt)
- {
- m_freem(m);
- return (0);
- }
- ether_demux(ifp, m);
- return (0);
}
/**
- * Handle mbufs on the outgoing hook, frames going to the interface
+ * Output processing task, handles outgoing frames
*/
-static int ng_vboxnetflt_rcv_out(hook_p hook, item_p item)
+static void vboxNetFltFreeBSDoutput(void *arg, int pending)
{
+ PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg;
struct mbuf *m, *m0;
- struct m_tag *mtag;
- const node_p node = NG_HOOK_NODE(hook);
- PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
struct ifnet *ifp = pThis->u.s.ifp;
unsigned int cSegs = 0;
bool fDropIt = false, fActive;
PINTNETSG pSG;
- NGI_GET_M(item, m);
- NG_FREE_ITEM(item);
-
- fActive = ASMAtomicUoReadBool(&pThis->fActive);
- if (!fActive)
- return ether_output_frame(ifp, m);
-
vboxNetFltRetain(pThis, true /* fBusy */);
- /* Pass directly to interface if the packet originated from us */
- mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
- if (mtag != NULL)
+ for (;;)
{
- m_tag_unlink(m, mtag);
- m_tag_free(mtag);
- goto out;
- }
+ mtx_lock_spin(&pThis->u.s.outq.ifq_mtx);
+ _IF_DEQUEUE(&pThis->u.s.outq, m);
+ mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx);
+ if (m == NULL)
+ break;
- for (m0 = m; m0 != NULL; m0 = m0->m_next)
- {
- if (m0->m_len > 0)
- cSegs++;
- }
+ for (m0 = m; m0 != NULL; m0 = m0->m_next)
+ if (m0->m_len > 0)
+ cSegs++;
#ifdef PADD_RUNT_FRAMES_FROM_HOST
- if (m_length(m, NULL) < 60)
- cSegs++;
+ if (m_length(m, NULL) < 60)
+ cSegs++;
#endif
- /* Create a copy and deliver to the virtual switch */
- pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
- vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
- fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
- RTMemTmpFree(pSG);
+ /* Create a copy and deliver to the virtual switch */
+ pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
+ vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
+ fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
+ RTMemTmpFree(pSG);
-out:
+ if (fDropIt)
+ m_freem(m);
+ else
+ ether_output_frame(ifp, m);
+ }
vboxNetFltRelease(pThis, true /* fBusy */);
- if (fDropIt)
- {
- m_freem(m);
- return (0);
- }
-
- return ether_output_frame(ifp, m);
}
-static int ng_vboxnetflt_shutdown(node_p node)
-{
- PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
- bool fActive;
-
- /* Prevent node shutdown if we're active */
- fActive = ASMAtomicUoReadBool(&pThis->fActive);
- if (fActive)
- return (EBUSY);
- NG_NODE_UNREF(node);
- return (0);
-}
-
-static int ng_vboxnetflt_disconnect(hook_p hook)
-{
- return (0);
-}
-
/**
* Called to deliver a frame to either the host, the wire or both.
*/
@@ -536,13 +542,23 @@
/* Create a new netgraph node for this instance */
if (ng_make_node_common(&ng_vboxnetflt_typestruct, &node) != 0)
- return VERR_INTERNAL_ERROR;
+ return VERR_INTERNAL_ERROR;
RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.ifp, ifp);
pThis->u.s.node = node;
bcopy(IF_LLADDR(ifp), &pThis->u.s.Mac, ETHER_ADDR_LEN);
ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
+ /* Initialize deferred input queue */
+ bzero(&pThis->u.s.inq, sizeof(struct ifqueue));
+ mtx_init(&pThis->u.s.inq.ifq_mtx, "vboxnetflt inq", NULL, MTX_SPIN);
+ TASK_INIT(&pThis->u.s.tskin, 0, vboxNetFltFreeBSDinput, pThis);
+
+ /* Initialize deferred output queue */
+ bzero(&pThis->u.s.outq, sizeof(struct ifqueue));
+ mtx_init(&pThis->u.s.outq.ifq_mtx, "vboxnetflt outq", NULL, MTX_SPIN);
+ TASK_INIT(&pThis->u.s.tskout, 0, vboxNetFltFreeBSDoutput, pThis);
+
RTSpinlockRelease(pThis->hSpinlock, &Tmp);
NG_NODE_SET_PRIVATE(node, pThis);
@@ -571,7 +587,10 @@
}
if (ifp0 != NULL)
+ {
+ vboxNetFltOsDeleteInstance(pThis);
vboxNetFltOsInitInstance(pThis, NULL);
+ }
return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
}
@@ -579,6 +598,12 @@
void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
{
+ taskqueue_drain(taskqueue_fast, &pThis->u.s.tskin);
+ taskqueue_drain(taskqueue_fast, &pThis->u.s.tskout);
+
+ mtx_destroy(&pThis->u.s.inq.ifq_mtx);
+ mtx_destroy(&pThis->u.s.outq.ifq_mtx);
+
if (pThis->u.s.node != NULL)
ng_rmnode_self(pThis->u.s.node);
pThis->u.s.node = NULL;

View File

@ -592,7 +592,7 @@ include/virtualbox/xpcom/xpcom-config.h
%%QT4%%@dirrmtry share/icons
%%QT4%%@dirrmtry share/applications
@dirrm lib/virtualbox/components
@dirrm lib/virtualbox/additions
%%GUESTADDITIONS%%@dirrm lib/virtualbox/additions
@dirrm lib/virtualbox
@cwd /
%%KMODDIR%%/vboxdrv.ko

View File

@ -7,6 +7,7 @@
PORTNAME= virtualbox
DISTVERSION= 3.0.51r22902
PORTREVISION= 1
CATEGORIES= emulators kld
MASTER_SITES= http://tmp.chruetertee.ch/ \
http://freebsd.unixfreunde.de/sources/ \
@ -142,15 +143,21 @@ BROKEN= Does not compile on FreeBSD 6.X
KMK_ARCH= freebsd.x86
PLIST_SUB+= I386=""
.else
.if !exists(/usr/lib32)
IGNORE= requires 32-bit libraries installed under /usr/lib32
.endif
KMK_ARCH= freebsd.${ARCH}
PLIST_SUB+= I386="@comment "
.endif
.include <bsd.port.pre.mk>
pre-everything::
.if ${ARCH} == "amd64"
.if !exists(/usr/lib32)
@${ECHO} 'Requires 32-bit libraries installed under /usr/lib32.'
@${ECHO} 'Do: cd /usr/src; make build32 install32; ldconfig -v -m -R /usr/lib32'
@${FALSE}
.endif
.endif
post-patch:
@${ECHO} 'VBOX_PATH_APP_PRIVATE_ARCH = ${PREFIX}/lib/virtualbox' > ${WRKSRC}/LocalConfig.kmk
@${ECHO} 'VBOX_PATH_SHARED_LIBS = ${PREFIX}/lib/virtualbox' >> ${WRKSRC}/LocalConfig.kmk

View File

@ -0,0 +1,28 @@
Index: src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h
===================================================================
--- src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h (revision 23391)
+++ src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h (working copy)
@@ -206,6 +206,14 @@
hook_p output;
/** Original interface flags */
unsigned int flags;
+ /** Input queue */
+ struct ifqueue inq;
+ /** Output queue */
+ struct ifqueue outq;
+ /** Input task */
+ struct task tskin;
+ /** Output task */
+ struct task tskout;
/** The MAC address of the interface. */
RTMAC Mac;
/** @} */
@@ -241,6 +249,8 @@
# endif
#elif defined(RT_OS_LINUX)
uint8_t abPadding[320];
+#elif defined(RT_OS_FREEBSD)
+ uint8_t abPadding[256];
#else
uint8_t abPadding[128];
#endif

View File

@ -0,0 +1,375 @@
Index: src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c
===================================================================
--- src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c (revision 23391)
+++ src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c (working copy)
@@ -43,6 +43,8 @@
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/syscallsubr.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
#include <net/if.h>
#include <net/if_var.h>
@@ -78,8 +80,6 @@
static ng_rcvdata_t ng_vboxnetflt_rcvdata;
static ng_disconnect_t ng_vboxnetflt_disconnect;
static int ng_vboxnetflt_mod_event(module_t mod, int event, void *data);
-static int ng_vboxnetflt_rcv_in(hook_p node, item_p item);
-static int ng_vboxnetflt_rcv_out(hook_p node, item_p item);
/** Netgraph node type */
#define NG_VBOXNETFLT_NODE_TYPE "vboxnetflt"
@@ -112,8 +112,8 @@
{
.version = NG_ABI_VERSION,
.name = NG_VBOXNETFLT_NODE_TYPE,
- .mod_event = vboxnetflt_modevent,
- .constructor = ng_vboxnetflt_constructor,
+ .mod_event = vboxnetflt_modevent,
+ .constructor = ng_vboxnetflt_constructor,
.rcvmsg = ng_vboxnetflt_rcvmsg,
.shutdown = ng_vboxnetflt_shutdown,
.newhook = ng_vboxnetflt_newhook,
@@ -267,16 +267,12 @@
if (strcmp(name, NG_VBOXNETFLT_HOOK_IN) == 0)
{
#if __FreeBSD_version >= 800000
- NG_HOOK_SET_RCVDATA(hook, ng_vboxnetflt_rcv_in);
NG_HOOK_SET_TO_INBOUND(hook);
#endif
pThis->u.s.input = hook;
}
else if (strcmp(name, NG_VBOXNETFLT_HOOK_OUT) == 0)
{
-#if __FreeBSD_version >= 800000
- NG_HOOK_SET_RCVDATA(hook, ng_vboxnetflt_rcv_out);
-#endif
pThis->u.s.output = hook;
}
else
@@ -310,161 +306,171 @@
/**
* Handle data on netgraph hooks.
+ * Frames processing is deferred to a taskqueue because this might
+ * be called with non-sleepable locks held and code paths inside
+ * the virtual switch might sleep.
*/
static int ng_vboxnetflt_rcvdata(hook_p hook, item_p item)
{
const node_p node = NG_HOOK_NODE(hook);
PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
+ struct ifnet *ifp = pThis->u.s.ifp;
struct mbuf *m;
+ struct m_tag *mtag;
+ bool fActive;
+ fActive = ASMAtomicUoReadBool(&pThis->fActive);
+
+ NGI_GET_M(item, m);
+ NG_FREE_ITEM(item);
+
+ /* Locate tag to see if processing should be skipped for this frame */
+ mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
+ if (mtag != NULL)
+ {
+ m_tag_unlink(m, mtag);
+ m_tag_free(mtag);
+ }
+
+ /*
+ * Handle incoming hook. This is connected to the
+ * input path of the interface, thus handling incoming frames.
+ */
if (pThis->u.s.input == hook)
- return ng_vboxnetflt_rcv_in(hook, item);
+ {
+ if (mtag != NULL || !fActive)
+ {
+ ether_demux(ifp, m);
+ return (0);
+ }
+ mtx_lock_spin(&pThis->u.s.inq.ifq_mtx);
+ _IF_ENQUEUE(&pThis->u.s.inq, m);
+ mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx);
+ taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskin);
+ }
+ /**
+ * Handle mbufs on the outgoing hook, frames going to the interface
+ */
else if (pThis->u.s.output == hook)
- return ng_vboxnetflt_rcv_out(hook, item);
+ {
+ if (mtag != NULL || !fActive)
+ return ether_output_frame(ifp, m);
+ mtx_lock_spin(&pThis->u.s.outq.ifq_mtx);
+ _IF_ENQUEUE(&pThis->u.s.outq, m);
+ mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx);
+ taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskout);
+ }
else
{
- NGI_GET_M(item, m);
- NG_FREE_ITEM(item);
+ m_freem(m);
}
return (0);
}
+static int ng_vboxnetflt_shutdown(node_p node)
+{
+ PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
+ bool fActive;
+
+ /* Prevent node shutdown if we're active */
+ fActive = ASMAtomicUoReadBool(&pThis->fActive);
+ if (fActive)
+ return (EBUSY);
+ NG_NODE_UNREF(node);
+ return (0);
+}
+
+static int ng_vboxnetflt_disconnect(hook_p hook)
+{
+ return (0);
+}
+
/**
- * Handle incoming hook. This is connected to the
- * input path of the interface, thus handling incoming frames.
+ * Input processing task, handles incoming frames
*/
-static int ng_vboxnetflt_rcv_in(hook_p hook, item_p item)
+static void vboxNetFltFreeBSDinput(void *arg, int pending)
{
+ PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg;
struct mbuf *m, *m0;
- struct m_tag *mtag;
- const node_p node = NG_HOOK_NODE(hook);
- PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
struct ifnet *ifp = pThis->u.s.ifp;
- bool fActive, fDropIt = false;
unsigned int cSegs = 0;
+ bool fDropIt = false, fActive;
PINTNETSG pSG;
- NGI_GET_M(item, m);
- NG_FREE_ITEM(item);
-
- fActive = ASMAtomicUoReadBool(&pThis->fActive);
- if (!fActive)
- goto out;
-
- mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
- if (mtag != NULL)
- {
- m_tag_unlink(m, mtag);
- m_tag_free(mtag);
- goto out;
- }
vboxNetFltRetain(pThis, true /* fBusy */);
-
- for (m0 = m; m0 != NULL; m0 = m0->m_next)
+ for (;;)
{
- if (m0->m_len > 0)
- cSegs++;
- }
+ mtx_lock_spin(&pThis->u.s.inq.ifq_mtx);
+ _IF_DEQUEUE(&pThis->u.s.inq, m);
+ mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx);
+ if (m == NULL)
+ break;
+ for (m0 = m; m0 != NULL; m0 = m0->m_next)
+ if (m0->m_len > 0)
+ cSegs++;
+
#ifdef PADD_RUNT_FRAMES_FROM_HOST
- if (m_length(m, NULL) < 60)
- cSegs++;
+ if (m_length(m, NULL) < 60)
+ cSegs++;
#endif
- /* Create a copy of the mbuf and hand it to the virtual switch */
- pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
- vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
- fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_WIRE);
- RTMemTmpFree(pSG);
+ /* Create a copy and deliver to the virtual switch */
+ pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
+ vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
+ fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
+ RTMemTmpFree(pSG);
+ if (fDropIt)
+ m_freem(m);
+ else
+ ether_demux(ifp, m);
+ }
vboxNetFltRelease(pThis, true /* fBusy */);
-
-out:
- /* Only deliver it to the host stack if the destination weren't a guest */
- if (fDropIt)
- {
- m_freem(m);
- return (0);
- }
- ether_demux(ifp, m);
- return (0);
}
/**
- * Handle mbufs on the outgoing hook, frames going to the interface
+ * Output processing task, handles outgoing frames
*/
-static int ng_vboxnetflt_rcv_out(hook_p hook, item_p item)
+static void vboxNetFltFreeBSDoutput(void *arg, int pending)
{
+ PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg;
struct mbuf *m, *m0;
- struct m_tag *mtag;
- const node_p node = NG_HOOK_NODE(hook);
- PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
struct ifnet *ifp = pThis->u.s.ifp;
unsigned int cSegs = 0;
bool fDropIt = false, fActive;
PINTNETSG pSG;
- NGI_GET_M(item, m);
- NG_FREE_ITEM(item);
-
- fActive = ASMAtomicUoReadBool(&pThis->fActive);
- if (!fActive)
- return ether_output_frame(ifp, m);
-
vboxNetFltRetain(pThis, true /* fBusy */);
- /* Pass directly to interface if the packet originated from us */
- mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
- if (mtag != NULL)
+ for (;;)
{
- m_tag_unlink(m, mtag);
- m_tag_free(mtag);
- goto out;
- }
+ mtx_lock_spin(&pThis->u.s.outq.ifq_mtx);
+ _IF_DEQUEUE(&pThis->u.s.outq, m);
+ mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx);
+ if (m == NULL)
+ break;
- for (m0 = m; m0 != NULL; m0 = m0->m_next)
- {
- if (m0->m_len > 0)
- cSegs++;
- }
+ for (m0 = m; m0 != NULL; m0 = m0->m_next)
+ if (m0->m_len > 0)
+ cSegs++;
#ifdef PADD_RUNT_FRAMES_FROM_HOST
- if (m_length(m, NULL) < 60)
- cSegs++;
+ if (m_length(m, NULL) < 60)
+ cSegs++;
#endif
- /* Create a copy and deliver to the virtual switch */
- pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
- vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
- fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
- RTMemTmpFree(pSG);
+ /* Create a copy and deliver to the virtual switch */
+ pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
+ vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
+ fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
+ RTMemTmpFree(pSG);
-out:
+ if (fDropIt)
+ m_freem(m);
+ else
+ ether_output_frame(ifp, m);
+ }
vboxNetFltRelease(pThis, true /* fBusy */);
- if (fDropIt)
- {
- m_freem(m);
- return (0);
- }
-
- return ether_output_frame(ifp, m);
}
-static int ng_vboxnetflt_shutdown(node_p node)
-{
- PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
- bool fActive;
-
- /* Prevent node shutdown if we're active */
- fActive = ASMAtomicUoReadBool(&pThis->fActive);
- if (fActive)
- return (EBUSY);
- NG_NODE_UNREF(node);
- return (0);
-}
-
-static int ng_vboxnetflt_disconnect(hook_p hook)
-{
- return (0);
-}
-
/**
* Called to deliver a frame to either the host, the wire or both.
*/
@@ -536,13 +542,23 @@
/* Create a new netgraph node for this instance */
if (ng_make_node_common(&ng_vboxnetflt_typestruct, &node) != 0)
- return VERR_INTERNAL_ERROR;
+ return VERR_INTERNAL_ERROR;
RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.ifp, ifp);
pThis->u.s.node = node;
bcopy(IF_LLADDR(ifp), &pThis->u.s.Mac, ETHER_ADDR_LEN);
ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
+ /* Initialize deferred input queue */
+ bzero(&pThis->u.s.inq, sizeof(struct ifqueue));
+ mtx_init(&pThis->u.s.inq.ifq_mtx, "vboxnetflt inq", NULL, MTX_SPIN);
+ TASK_INIT(&pThis->u.s.tskin, 0, vboxNetFltFreeBSDinput, pThis);
+
+ /* Initialize deferred output queue */
+ bzero(&pThis->u.s.outq, sizeof(struct ifqueue));
+ mtx_init(&pThis->u.s.outq.ifq_mtx, "vboxnetflt outq", NULL, MTX_SPIN);
+ TASK_INIT(&pThis->u.s.tskout, 0, vboxNetFltFreeBSDoutput, pThis);
+
RTSpinlockRelease(pThis->hSpinlock, &Tmp);
NG_NODE_SET_PRIVATE(node, pThis);
@@ -571,7 +587,10 @@
}
if (ifp0 != NULL)
+ {
+ vboxNetFltOsDeleteInstance(pThis);
vboxNetFltOsInitInstance(pThis, NULL);
+ }
return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
}
@@ -579,6 +598,12 @@
void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
{
+ taskqueue_drain(taskqueue_fast, &pThis->u.s.tskin);
+ taskqueue_drain(taskqueue_fast, &pThis->u.s.tskout);
+
+ mtx_destroy(&pThis->u.s.inq.ifq_mtx);
+ mtx_destroy(&pThis->u.s.outq.ifq_mtx);
+
if (pThis->u.s.node != NULL)
ng_rmnode_self(pThis->u.s.node);
pThis->u.s.node = NULL;

View File

@ -592,7 +592,7 @@ include/virtualbox/xpcom/xpcom-config.h
%%QT4%%@dirrmtry share/icons
%%QT4%%@dirrmtry share/applications
@dirrm lib/virtualbox/components
@dirrm lib/virtualbox/additions
%%GUESTADDITIONS%%@dirrm lib/virtualbox/additions
@dirrm lib/virtualbox
@cwd /
%%KMODDIR%%/vboxdrv.ko

View File

@ -7,6 +7,7 @@
PORTNAME= virtualbox
DISTVERSION= 3.0.51r22902
PORTREVISION= 1
CATEGORIES= emulators kld
MASTER_SITES= http://tmp.chruetertee.ch/ \
http://freebsd.unixfreunde.de/sources/ \
@ -142,15 +143,21 @@ BROKEN= Does not compile on FreeBSD 6.X
KMK_ARCH= freebsd.x86
PLIST_SUB+= I386=""
.else
.if !exists(/usr/lib32)
IGNORE= requires 32-bit libraries installed under /usr/lib32
.endif
KMK_ARCH= freebsd.${ARCH}
PLIST_SUB+= I386="@comment "
.endif
.include <bsd.port.pre.mk>
pre-everything::
.if ${ARCH} == "amd64"
.if !exists(/usr/lib32)
@${ECHO} 'Requires 32-bit libraries installed under /usr/lib32.'
@${ECHO} 'Do: cd /usr/src; make build32 install32; ldconfig -v -m -R /usr/lib32'
@${FALSE}
.endif
.endif
post-patch:
@${ECHO} 'VBOX_PATH_APP_PRIVATE_ARCH = ${PREFIX}/lib/virtualbox' > ${WRKSRC}/LocalConfig.kmk
@${ECHO} 'VBOX_PATH_SHARED_LIBS = ${PREFIX}/lib/virtualbox' >> ${WRKSRC}/LocalConfig.kmk

View File

@ -0,0 +1,28 @@
Index: src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h
===================================================================
--- src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h (revision 23391)
+++ src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h (working copy)
@@ -206,6 +206,14 @@
hook_p output;
/** Original interface flags */
unsigned int flags;
+ /** Input queue */
+ struct ifqueue inq;
+ /** Output queue */
+ struct ifqueue outq;
+ /** Input task */
+ struct task tskin;
+ /** Output task */
+ struct task tskout;
/** The MAC address of the interface. */
RTMAC Mac;
/** @} */
@@ -241,6 +249,8 @@
# endif
#elif defined(RT_OS_LINUX)
uint8_t abPadding[320];
+#elif defined(RT_OS_FREEBSD)
+ uint8_t abPadding[256];
#else
uint8_t abPadding[128];
#endif

View File

@ -0,0 +1,375 @@
Index: src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c
===================================================================
--- src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c (revision 23391)
+++ src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c (working copy)
@@ -43,6 +43,8 @@
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/syscallsubr.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
#include <net/if.h>
#include <net/if_var.h>
@@ -78,8 +80,6 @@
static ng_rcvdata_t ng_vboxnetflt_rcvdata;
static ng_disconnect_t ng_vboxnetflt_disconnect;
static int ng_vboxnetflt_mod_event(module_t mod, int event, void *data);
-static int ng_vboxnetflt_rcv_in(hook_p node, item_p item);
-static int ng_vboxnetflt_rcv_out(hook_p node, item_p item);
/** Netgraph node type */
#define NG_VBOXNETFLT_NODE_TYPE "vboxnetflt"
@@ -112,8 +112,8 @@
{
.version = NG_ABI_VERSION,
.name = NG_VBOXNETFLT_NODE_TYPE,
- .mod_event = vboxnetflt_modevent,
- .constructor = ng_vboxnetflt_constructor,
+ .mod_event = vboxnetflt_modevent,
+ .constructor = ng_vboxnetflt_constructor,
.rcvmsg = ng_vboxnetflt_rcvmsg,
.shutdown = ng_vboxnetflt_shutdown,
.newhook = ng_vboxnetflt_newhook,
@@ -267,16 +267,12 @@
if (strcmp(name, NG_VBOXNETFLT_HOOK_IN) == 0)
{
#if __FreeBSD_version >= 800000
- NG_HOOK_SET_RCVDATA(hook, ng_vboxnetflt_rcv_in);
NG_HOOK_SET_TO_INBOUND(hook);
#endif
pThis->u.s.input = hook;
}
else if (strcmp(name, NG_VBOXNETFLT_HOOK_OUT) == 0)
{
-#if __FreeBSD_version >= 800000
- NG_HOOK_SET_RCVDATA(hook, ng_vboxnetflt_rcv_out);
-#endif
pThis->u.s.output = hook;
}
else
@@ -310,161 +306,171 @@
/**
* Handle data on netgraph hooks.
+ * Frames processing is deferred to a taskqueue because this might
+ * be called with non-sleepable locks held and code paths inside
+ * the virtual switch might sleep.
*/
static int ng_vboxnetflt_rcvdata(hook_p hook, item_p item)
{
const node_p node = NG_HOOK_NODE(hook);
PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
+ struct ifnet *ifp = pThis->u.s.ifp;
struct mbuf *m;
+ struct m_tag *mtag;
+ bool fActive;
+ fActive = ASMAtomicUoReadBool(&pThis->fActive);
+
+ NGI_GET_M(item, m);
+ NG_FREE_ITEM(item);
+
+ /* Locate tag to see if processing should be skipped for this frame */
+ mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
+ if (mtag != NULL)
+ {
+ m_tag_unlink(m, mtag);
+ m_tag_free(mtag);
+ }
+
+ /*
+ * Handle incoming hook. This is connected to the
+ * input path of the interface, thus handling incoming frames.
+ */
if (pThis->u.s.input == hook)
- return ng_vboxnetflt_rcv_in(hook, item);
+ {
+ if (mtag != NULL || !fActive)
+ {
+ ether_demux(ifp, m);
+ return (0);
+ }
+ mtx_lock_spin(&pThis->u.s.inq.ifq_mtx);
+ _IF_ENQUEUE(&pThis->u.s.inq, m);
+ mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx);
+ taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskin);
+ }
+ /**
+ * Handle mbufs on the outgoing hook, frames going to the interface
+ */
else if (pThis->u.s.output == hook)
- return ng_vboxnetflt_rcv_out(hook, item);
+ {
+ if (mtag != NULL || !fActive)
+ return ether_output_frame(ifp, m);
+ mtx_lock_spin(&pThis->u.s.outq.ifq_mtx);
+ _IF_ENQUEUE(&pThis->u.s.outq, m);
+ mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx);
+ taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskout);
+ }
else
{
- NGI_GET_M(item, m);
- NG_FREE_ITEM(item);
+ m_freem(m);
}
return (0);
}
+static int ng_vboxnetflt_shutdown(node_p node)
+{
+ PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
+ bool fActive;
+
+ /* Prevent node shutdown if we're active */
+ fActive = ASMAtomicUoReadBool(&pThis->fActive);
+ if (fActive)
+ return (EBUSY);
+ NG_NODE_UNREF(node);
+ return (0);
+}
+
+static int ng_vboxnetflt_disconnect(hook_p hook)
+{
+ return (0);
+}
+
/**
- * Handle incoming hook. This is connected to the
- * input path of the interface, thus handling incoming frames.
+ * Input processing task, handles incoming frames
*/
-static int ng_vboxnetflt_rcv_in(hook_p hook, item_p item)
+static void vboxNetFltFreeBSDinput(void *arg, int pending)
{
+ PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg;
struct mbuf *m, *m0;
- struct m_tag *mtag;
- const node_p node = NG_HOOK_NODE(hook);
- PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
struct ifnet *ifp = pThis->u.s.ifp;
- bool fActive, fDropIt = false;
unsigned int cSegs = 0;
+ bool fDropIt = false, fActive;
PINTNETSG pSG;
- NGI_GET_M(item, m);
- NG_FREE_ITEM(item);
-
- fActive = ASMAtomicUoReadBool(&pThis->fActive);
- if (!fActive)
- goto out;
-
- mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
- if (mtag != NULL)
- {
- m_tag_unlink(m, mtag);
- m_tag_free(mtag);
- goto out;
- }
vboxNetFltRetain(pThis, true /* fBusy */);
-
- for (m0 = m; m0 != NULL; m0 = m0->m_next)
+ for (;;)
{
- if (m0->m_len > 0)
- cSegs++;
- }
+ mtx_lock_spin(&pThis->u.s.inq.ifq_mtx);
+ _IF_DEQUEUE(&pThis->u.s.inq, m);
+ mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx);
+ if (m == NULL)
+ break;
+ for (m0 = m; m0 != NULL; m0 = m0->m_next)
+ if (m0->m_len > 0)
+ cSegs++;
+
#ifdef PADD_RUNT_FRAMES_FROM_HOST
- if (m_length(m, NULL) < 60)
- cSegs++;
+ if (m_length(m, NULL) < 60)
+ cSegs++;
#endif
- /* Create a copy of the mbuf and hand it to the virtual switch */
- pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
- vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
- fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_WIRE);
- RTMemTmpFree(pSG);
+ /* Create a copy and deliver to the virtual switch */
+ pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
+ vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
+ fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
+ RTMemTmpFree(pSG);
+ if (fDropIt)
+ m_freem(m);
+ else
+ ether_demux(ifp, m);
+ }
vboxNetFltRelease(pThis, true /* fBusy */);
-
-out:
- /* Only deliver it to the host stack if the destination weren't a guest */
- if (fDropIt)
- {
- m_freem(m);
- return (0);
- }
- ether_demux(ifp, m);
- return (0);
}
/**
- * Handle mbufs on the outgoing hook, frames going to the interface
+ * Output processing task, handles outgoing frames
*/
-static int ng_vboxnetflt_rcv_out(hook_p hook, item_p item)
+static void vboxNetFltFreeBSDoutput(void *arg, int pending)
{
+ PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg;
struct mbuf *m, *m0;
- struct m_tag *mtag;
- const node_p node = NG_HOOK_NODE(hook);
- PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
struct ifnet *ifp = pThis->u.s.ifp;
unsigned int cSegs = 0;
bool fDropIt = false, fActive;
PINTNETSG pSG;
- NGI_GET_M(item, m);
- NG_FREE_ITEM(item);
-
- fActive = ASMAtomicUoReadBool(&pThis->fActive);
- if (!fActive)
- return ether_output_frame(ifp, m);
-
vboxNetFltRetain(pThis, true /* fBusy */);
- /* Pass directly to interface if the packet originated from us */
- mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
- if (mtag != NULL)
+ for (;;)
{
- m_tag_unlink(m, mtag);
- m_tag_free(mtag);
- goto out;
- }
+ mtx_lock_spin(&pThis->u.s.outq.ifq_mtx);
+ _IF_DEQUEUE(&pThis->u.s.outq, m);
+ mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx);
+ if (m == NULL)
+ break;
- for (m0 = m; m0 != NULL; m0 = m0->m_next)
- {
- if (m0->m_len > 0)
- cSegs++;
- }
+ for (m0 = m; m0 != NULL; m0 = m0->m_next)
+ if (m0->m_len > 0)
+ cSegs++;
#ifdef PADD_RUNT_FRAMES_FROM_HOST
- if (m_length(m, NULL) < 60)
- cSegs++;
+ if (m_length(m, NULL) < 60)
+ cSegs++;
#endif
- /* Create a copy and deliver to the virtual switch */
- pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
- vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
- fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
- RTMemTmpFree(pSG);
+ /* Create a copy and deliver to the virtual switch */
+ pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
+ vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
+ fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
+ RTMemTmpFree(pSG);
-out:
+ if (fDropIt)
+ m_freem(m);
+ else
+ ether_output_frame(ifp, m);
+ }
vboxNetFltRelease(pThis, true /* fBusy */);
- if (fDropIt)
- {
- m_freem(m);
- return (0);
- }
-
- return ether_output_frame(ifp, m);
}
-static int ng_vboxnetflt_shutdown(node_p node)
-{
- PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
- bool fActive;
-
- /* Prevent node shutdown if we're active */
- fActive = ASMAtomicUoReadBool(&pThis->fActive);
- if (fActive)
- return (EBUSY);
- NG_NODE_UNREF(node);
- return (0);
-}
-
-static int ng_vboxnetflt_disconnect(hook_p hook)
-{
- return (0);
-}
-
/**
* Called to deliver a frame to either the host, the wire or both.
*/
@@ -536,13 +542,23 @@
/* Create a new netgraph node for this instance */
if (ng_make_node_common(&ng_vboxnetflt_typestruct, &node) != 0)
- return VERR_INTERNAL_ERROR;
+ return VERR_INTERNAL_ERROR;
RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.ifp, ifp);
pThis->u.s.node = node;
bcopy(IF_LLADDR(ifp), &pThis->u.s.Mac, ETHER_ADDR_LEN);
ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
+ /* Initialize deferred input queue */
+ bzero(&pThis->u.s.inq, sizeof(struct ifqueue));
+ mtx_init(&pThis->u.s.inq.ifq_mtx, "vboxnetflt inq", NULL, MTX_SPIN);
+ TASK_INIT(&pThis->u.s.tskin, 0, vboxNetFltFreeBSDinput, pThis);
+
+ /* Initialize deferred output queue */
+ bzero(&pThis->u.s.outq, sizeof(struct ifqueue));
+ mtx_init(&pThis->u.s.outq.ifq_mtx, "vboxnetflt outq", NULL, MTX_SPIN);
+ TASK_INIT(&pThis->u.s.tskout, 0, vboxNetFltFreeBSDoutput, pThis);
+
RTSpinlockRelease(pThis->hSpinlock, &Tmp);
NG_NODE_SET_PRIVATE(node, pThis);
@@ -571,7 +587,10 @@
}
if (ifp0 != NULL)
+ {
+ vboxNetFltOsDeleteInstance(pThis);
vboxNetFltOsInitInstance(pThis, NULL);
+ }
return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
}
@@ -579,6 +598,12 @@
void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
{
+ taskqueue_drain(taskqueue_fast, &pThis->u.s.tskin);
+ taskqueue_drain(taskqueue_fast, &pThis->u.s.tskout);
+
+ mtx_destroy(&pThis->u.s.inq.ifq_mtx);
+ mtx_destroy(&pThis->u.s.outq.ifq_mtx);
+
if (pThis->u.s.node != NULL)
ng_rmnode_self(pThis->u.s.node);
pThis->u.s.node = NULL;

View File

@ -592,7 +592,7 @@ include/virtualbox/xpcom/xpcom-config.h
%%QT4%%@dirrmtry share/icons
%%QT4%%@dirrmtry share/applications
@dirrm lib/virtualbox/components
@dirrm lib/virtualbox/additions
%%GUESTADDITIONS%%@dirrm lib/virtualbox/additions
@dirrm lib/virtualbox
@cwd /
%%KMODDIR%%/vboxdrv.ko

View File

@ -7,6 +7,7 @@
PORTNAME= virtualbox
DISTVERSION= 3.0.51r22902
PORTREVISION= 1
CATEGORIES= emulators kld
MASTER_SITES= http://tmp.chruetertee.ch/ \
http://freebsd.unixfreunde.de/sources/ \
@ -142,15 +143,21 @@ BROKEN= Does not compile on FreeBSD 6.X
KMK_ARCH= freebsd.x86
PLIST_SUB+= I386=""
.else
.if !exists(/usr/lib32)
IGNORE= requires 32-bit libraries installed under /usr/lib32
.endif
KMK_ARCH= freebsd.${ARCH}
PLIST_SUB+= I386="@comment "
.endif
.include <bsd.port.pre.mk>
pre-everything::
.if ${ARCH} == "amd64"
.if !exists(/usr/lib32)
@${ECHO} 'Requires 32-bit libraries installed under /usr/lib32.'
@${ECHO} 'Do: cd /usr/src; make build32 install32; ldconfig -v -m -R /usr/lib32'
@${FALSE}
.endif
.endif
post-patch:
@${ECHO} 'VBOX_PATH_APP_PRIVATE_ARCH = ${PREFIX}/lib/virtualbox' > ${WRKSRC}/LocalConfig.kmk
@${ECHO} 'VBOX_PATH_SHARED_LIBS = ${PREFIX}/lib/virtualbox' >> ${WRKSRC}/LocalConfig.kmk

View File

@ -0,0 +1,28 @@
Index: src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h
===================================================================
--- src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h (revision 23391)
+++ src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h (working copy)
@@ -206,6 +206,14 @@
hook_p output;
/** Original interface flags */
unsigned int flags;
+ /** Input queue */
+ struct ifqueue inq;
+ /** Output queue */
+ struct ifqueue outq;
+ /** Input task */
+ struct task tskin;
+ /** Output task */
+ struct task tskout;
/** The MAC address of the interface. */
RTMAC Mac;
/** @} */
@@ -241,6 +249,8 @@
# endif
#elif defined(RT_OS_LINUX)
uint8_t abPadding[320];
+#elif defined(RT_OS_FREEBSD)
+ uint8_t abPadding[256];
#else
uint8_t abPadding[128];
#endif

View File

@ -0,0 +1,375 @@
Index: src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c
===================================================================
--- src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c (revision 23391)
+++ src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c (working copy)
@@ -43,6 +43,8 @@
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/syscallsubr.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
#include <net/if.h>
#include <net/if_var.h>
@@ -78,8 +80,6 @@
static ng_rcvdata_t ng_vboxnetflt_rcvdata;
static ng_disconnect_t ng_vboxnetflt_disconnect;
static int ng_vboxnetflt_mod_event(module_t mod, int event, void *data);
-static int ng_vboxnetflt_rcv_in(hook_p node, item_p item);
-static int ng_vboxnetflt_rcv_out(hook_p node, item_p item);
/** Netgraph node type */
#define NG_VBOXNETFLT_NODE_TYPE "vboxnetflt"
@@ -112,8 +112,8 @@
{
.version = NG_ABI_VERSION,
.name = NG_VBOXNETFLT_NODE_TYPE,
- .mod_event = vboxnetflt_modevent,
- .constructor = ng_vboxnetflt_constructor,
+ .mod_event = vboxnetflt_modevent,
+ .constructor = ng_vboxnetflt_constructor,
.rcvmsg = ng_vboxnetflt_rcvmsg,
.shutdown = ng_vboxnetflt_shutdown,
.newhook = ng_vboxnetflt_newhook,
@@ -267,16 +267,12 @@
if (strcmp(name, NG_VBOXNETFLT_HOOK_IN) == 0)
{
#if __FreeBSD_version >= 800000
- NG_HOOK_SET_RCVDATA(hook, ng_vboxnetflt_rcv_in);
NG_HOOK_SET_TO_INBOUND(hook);
#endif
pThis->u.s.input = hook;
}
else if (strcmp(name, NG_VBOXNETFLT_HOOK_OUT) == 0)
{
-#if __FreeBSD_version >= 800000
- NG_HOOK_SET_RCVDATA(hook, ng_vboxnetflt_rcv_out);
-#endif
pThis->u.s.output = hook;
}
else
@@ -310,161 +306,171 @@
/**
* Handle data on netgraph hooks.
+ * Frames processing is deferred to a taskqueue because this might
+ * be called with non-sleepable locks held and code paths inside
+ * the virtual switch might sleep.
*/
static int ng_vboxnetflt_rcvdata(hook_p hook, item_p item)
{
const node_p node = NG_HOOK_NODE(hook);
PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
+ struct ifnet *ifp = pThis->u.s.ifp;
struct mbuf *m;
+ struct m_tag *mtag;
+ bool fActive;
+ fActive = ASMAtomicUoReadBool(&pThis->fActive);
+
+ NGI_GET_M(item, m);
+ NG_FREE_ITEM(item);
+
+ /* Locate tag to see if processing should be skipped for this frame */
+ mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
+ if (mtag != NULL)
+ {
+ m_tag_unlink(m, mtag);
+ m_tag_free(mtag);
+ }
+
+ /*
+ * Handle incoming hook. This is connected to the
+ * input path of the interface, thus handling incoming frames.
+ */
if (pThis->u.s.input == hook)
- return ng_vboxnetflt_rcv_in(hook, item);
+ {
+ if (mtag != NULL || !fActive)
+ {
+ ether_demux(ifp, m);
+ return (0);
+ }
+ mtx_lock_spin(&pThis->u.s.inq.ifq_mtx);
+ _IF_ENQUEUE(&pThis->u.s.inq, m);
+ mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx);
+ taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskin);
+ }
+ /**
+ * Handle mbufs on the outgoing hook, frames going to the interface
+ */
else if (pThis->u.s.output == hook)
- return ng_vboxnetflt_rcv_out(hook, item);
+ {
+ if (mtag != NULL || !fActive)
+ return ether_output_frame(ifp, m);
+ mtx_lock_spin(&pThis->u.s.outq.ifq_mtx);
+ _IF_ENQUEUE(&pThis->u.s.outq, m);
+ mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx);
+ taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskout);
+ }
else
{
- NGI_GET_M(item, m);
- NG_FREE_ITEM(item);
+ m_freem(m);
}
return (0);
}
+static int ng_vboxnetflt_shutdown(node_p node)
+{
+ PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
+ bool fActive;
+
+ /* Prevent node shutdown if we're active */
+ fActive = ASMAtomicUoReadBool(&pThis->fActive);
+ if (fActive)
+ return (EBUSY);
+ NG_NODE_UNREF(node);
+ return (0);
+}
+
+static int ng_vboxnetflt_disconnect(hook_p hook)
+{
+ return (0);
+}
+
/**
- * Handle incoming hook. This is connected to the
- * input path of the interface, thus handling incoming frames.
+ * Input processing task, handles incoming frames
*/
-static int ng_vboxnetflt_rcv_in(hook_p hook, item_p item)
+static void vboxNetFltFreeBSDinput(void *arg, int pending)
{
+ PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg;
struct mbuf *m, *m0;
- struct m_tag *mtag;
- const node_p node = NG_HOOK_NODE(hook);
- PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
struct ifnet *ifp = pThis->u.s.ifp;
- bool fActive, fDropIt = false;
unsigned int cSegs = 0;
+ bool fDropIt = false, fActive;
PINTNETSG pSG;
- NGI_GET_M(item, m);
- NG_FREE_ITEM(item);
-
- fActive = ASMAtomicUoReadBool(&pThis->fActive);
- if (!fActive)
- goto out;
-
- mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
- if (mtag != NULL)
- {
- m_tag_unlink(m, mtag);
- m_tag_free(mtag);
- goto out;
- }
vboxNetFltRetain(pThis, true /* fBusy */);
-
- for (m0 = m; m0 != NULL; m0 = m0->m_next)
+ for (;;)
{
- if (m0->m_len > 0)
- cSegs++;
- }
+ mtx_lock_spin(&pThis->u.s.inq.ifq_mtx);
+ _IF_DEQUEUE(&pThis->u.s.inq, m);
+ mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx);
+ if (m == NULL)
+ break;
+ for (m0 = m; m0 != NULL; m0 = m0->m_next)
+ if (m0->m_len > 0)
+ cSegs++;
+
#ifdef PADD_RUNT_FRAMES_FROM_HOST
- if (m_length(m, NULL) < 60)
- cSegs++;
+ if (m_length(m, NULL) < 60)
+ cSegs++;
#endif
- /* Create a copy of the mbuf and hand it to the virtual switch */
- pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
- vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
- fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_WIRE);
- RTMemTmpFree(pSG);
+ /* Create a copy and deliver to the virtual switch */
+ pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
+ vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
+ fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
+ RTMemTmpFree(pSG);
+ if (fDropIt)
+ m_freem(m);
+ else
+ ether_demux(ifp, m);
+ }
vboxNetFltRelease(pThis, true /* fBusy */);
-
-out:
- /* Only deliver it to the host stack if the destination weren't a guest */
- if (fDropIt)
- {
- m_freem(m);
- return (0);
- }
- ether_demux(ifp, m);
- return (0);
}
/**
- * Handle mbufs on the outgoing hook, frames going to the interface
+ * Output processing task, handles outgoing frames
*/
-static int ng_vboxnetflt_rcv_out(hook_p hook, item_p item)
+static void vboxNetFltFreeBSDoutput(void *arg, int pending)
{
+ PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg;
struct mbuf *m, *m0;
- struct m_tag *mtag;
- const node_p node = NG_HOOK_NODE(hook);
- PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
struct ifnet *ifp = pThis->u.s.ifp;
unsigned int cSegs = 0;
bool fDropIt = false, fActive;
PINTNETSG pSG;
- NGI_GET_M(item, m);
- NG_FREE_ITEM(item);
-
- fActive = ASMAtomicUoReadBool(&pThis->fActive);
- if (!fActive)
- return ether_output_frame(ifp, m);
-
vboxNetFltRetain(pThis, true /* fBusy */);
- /* Pass directly to interface if the packet originated from us */
- mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
- if (mtag != NULL)
+ for (;;)
{
- m_tag_unlink(m, mtag);
- m_tag_free(mtag);
- goto out;
- }
+ mtx_lock_spin(&pThis->u.s.outq.ifq_mtx);
+ _IF_DEQUEUE(&pThis->u.s.outq, m);
+ mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx);
+ if (m == NULL)
+ break;
- for (m0 = m; m0 != NULL; m0 = m0->m_next)
- {
- if (m0->m_len > 0)
- cSegs++;
- }
+ for (m0 = m; m0 != NULL; m0 = m0->m_next)
+ if (m0->m_len > 0)
+ cSegs++;
#ifdef PADD_RUNT_FRAMES_FROM_HOST
- if (m_length(m, NULL) < 60)
- cSegs++;
+ if (m_length(m, NULL) < 60)
+ cSegs++;
#endif
- /* Create a copy and deliver to the virtual switch */
- pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
- vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
- fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
- RTMemTmpFree(pSG);
+ /* Create a copy and deliver to the virtual switch */
+ pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
+ vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
+ fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
+ RTMemTmpFree(pSG);
-out:
+ if (fDropIt)
+ m_freem(m);
+ else
+ ether_output_frame(ifp, m);
+ }
vboxNetFltRelease(pThis, true /* fBusy */);
- if (fDropIt)
- {
- m_freem(m);
- return (0);
- }
-
- return ether_output_frame(ifp, m);
}
-static int ng_vboxnetflt_shutdown(node_p node)
-{
- PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
- bool fActive;
-
- /* Prevent node shutdown if we're active */
- fActive = ASMAtomicUoReadBool(&pThis->fActive);
- if (fActive)
- return (EBUSY);
- NG_NODE_UNREF(node);
- return (0);
-}
-
-static int ng_vboxnetflt_disconnect(hook_p hook)
-{
- return (0);
-}
-
/**
* Called to deliver a frame to either the host, the wire or both.
*/
@@ -536,13 +542,23 @@
/* Create a new netgraph node for this instance */
if (ng_make_node_common(&ng_vboxnetflt_typestruct, &node) != 0)
- return VERR_INTERNAL_ERROR;
+ return VERR_INTERNAL_ERROR;
RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.ifp, ifp);
pThis->u.s.node = node;
bcopy(IF_LLADDR(ifp), &pThis->u.s.Mac, ETHER_ADDR_LEN);
ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
+ /* Initialize deferred input queue */
+ bzero(&pThis->u.s.inq, sizeof(struct ifqueue));
+ mtx_init(&pThis->u.s.inq.ifq_mtx, "vboxnetflt inq", NULL, MTX_SPIN);
+ TASK_INIT(&pThis->u.s.tskin, 0, vboxNetFltFreeBSDinput, pThis);
+
+ /* Initialize deferred output queue */
+ bzero(&pThis->u.s.outq, sizeof(struct ifqueue));
+ mtx_init(&pThis->u.s.outq.ifq_mtx, "vboxnetflt outq", NULL, MTX_SPIN);
+ TASK_INIT(&pThis->u.s.tskout, 0, vboxNetFltFreeBSDoutput, pThis);
+
RTSpinlockRelease(pThis->hSpinlock, &Tmp);
NG_NODE_SET_PRIVATE(node, pThis);
@@ -571,7 +587,10 @@
}
if (ifp0 != NULL)
+ {
+ vboxNetFltOsDeleteInstance(pThis);
vboxNetFltOsInitInstance(pThis, NULL);
+ }
return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
}
@@ -579,6 +598,12 @@
void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
{
+ taskqueue_drain(taskqueue_fast, &pThis->u.s.tskin);
+ taskqueue_drain(taskqueue_fast, &pThis->u.s.tskout);
+
+ mtx_destroy(&pThis->u.s.inq.ifq_mtx);
+ mtx_destroy(&pThis->u.s.outq.ifq_mtx);
+
if (pThis->u.s.node != NULL)
ng_rmnode_self(pThis->u.s.node);
pThis->u.s.node = NULL;

View File

@ -592,7 +592,7 @@ include/virtualbox/xpcom/xpcom-config.h
%%QT4%%@dirrmtry share/icons
%%QT4%%@dirrmtry share/applications
@dirrm lib/virtualbox/components
@dirrm lib/virtualbox/additions
%%GUESTADDITIONS%%@dirrm lib/virtualbox/additions
@dirrm lib/virtualbox
@cwd /
%%KMODDIR%%/vboxdrv.ko

View File

@ -7,6 +7,7 @@
PORTNAME= virtualbox
DISTVERSION= 3.0.51r22902
PORTREVISION= 1
CATEGORIES= emulators kld
MASTER_SITES= http://tmp.chruetertee.ch/ \
http://freebsd.unixfreunde.de/sources/ \
@ -142,15 +143,21 @@ BROKEN= Does not compile on FreeBSD 6.X
KMK_ARCH= freebsd.x86
PLIST_SUB+= I386=""
.else
.if !exists(/usr/lib32)
IGNORE= requires 32-bit libraries installed under /usr/lib32
.endif
KMK_ARCH= freebsd.${ARCH}
PLIST_SUB+= I386="@comment "
.endif
.include <bsd.port.pre.mk>
pre-everything::
.if ${ARCH} == "amd64"
.if !exists(/usr/lib32)
@${ECHO} 'Requires 32-bit libraries installed under /usr/lib32.'
@${ECHO} 'Do: cd /usr/src; make build32 install32; ldconfig -v -m -R /usr/lib32'
@${FALSE}
.endif
.endif
post-patch:
@${ECHO} 'VBOX_PATH_APP_PRIVATE_ARCH = ${PREFIX}/lib/virtualbox' > ${WRKSRC}/LocalConfig.kmk
@${ECHO} 'VBOX_PATH_SHARED_LIBS = ${PREFIX}/lib/virtualbox' >> ${WRKSRC}/LocalConfig.kmk

View File

@ -0,0 +1,28 @@
Index: src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h
===================================================================
--- src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h (revision 23391)
+++ src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h (working copy)
@@ -206,6 +206,14 @@
hook_p output;
/** Original interface flags */
unsigned int flags;
+ /** Input queue */
+ struct ifqueue inq;
+ /** Output queue */
+ struct ifqueue outq;
+ /** Input task */
+ struct task tskin;
+ /** Output task */
+ struct task tskout;
/** The MAC address of the interface. */
RTMAC Mac;
/** @} */
@@ -241,6 +249,8 @@
# endif
#elif defined(RT_OS_LINUX)
uint8_t abPadding[320];
+#elif defined(RT_OS_FREEBSD)
+ uint8_t abPadding[256];
#else
uint8_t abPadding[128];
#endif

View File

@ -0,0 +1,375 @@
Index: src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c
===================================================================
--- src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c (revision 23391)
+++ src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c (working copy)
@@ -43,6 +43,8 @@
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/syscallsubr.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
#include <net/if.h>
#include <net/if_var.h>
@@ -78,8 +80,6 @@
static ng_rcvdata_t ng_vboxnetflt_rcvdata;
static ng_disconnect_t ng_vboxnetflt_disconnect;
static int ng_vboxnetflt_mod_event(module_t mod, int event, void *data);
-static int ng_vboxnetflt_rcv_in(hook_p node, item_p item);
-static int ng_vboxnetflt_rcv_out(hook_p node, item_p item);
/** Netgraph node type */
#define NG_VBOXNETFLT_NODE_TYPE "vboxnetflt"
@@ -112,8 +112,8 @@
{
.version = NG_ABI_VERSION,
.name = NG_VBOXNETFLT_NODE_TYPE,
- .mod_event = vboxnetflt_modevent,
- .constructor = ng_vboxnetflt_constructor,
+ .mod_event = vboxnetflt_modevent,
+ .constructor = ng_vboxnetflt_constructor,
.rcvmsg = ng_vboxnetflt_rcvmsg,
.shutdown = ng_vboxnetflt_shutdown,
.newhook = ng_vboxnetflt_newhook,
@@ -267,16 +267,12 @@
if (strcmp(name, NG_VBOXNETFLT_HOOK_IN) == 0)
{
#if __FreeBSD_version >= 800000
- NG_HOOK_SET_RCVDATA(hook, ng_vboxnetflt_rcv_in);
NG_HOOK_SET_TO_INBOUND(hook);
#endif
pThis->u.s.input = hook;
}
else if (strcmp(name, NG_VBOXNETFLT_HOOK_OUT) == 0)
{
-#if __FreeBSD_version >= 800000
- NG_HOOK_SET_RCVDATA(hook, ng_vboxnetflt_rcv_out);
-#endif
pThis->u.s.output = hook;
}
else
@@ -310,161 +306,171 @@
/**
* Handle data on netgraph hooks.
+ * Frames processing is deferred to a taskqueue because this might
+ * be called with non-sleepable locks held and code paths inside
+ * the virtual switch might sleep.
*/
static int ng_vboxnetflt_rcvdata(hook_p hook, item_p item)
{
const node_p node = NG_HOOK_NODE(hook);
PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
+ struct ifnet *ifp = pThis->u.s.ifp;
struct mbuf *m;
+ struct m_tag *mtag;
+ bool fActive;
+ fActive = ASMAtomicUoReadBool(&pThis->fActive);
+
+ NGI_GET_M(item, m);
+ NG_FREE_ITEM(item);
+
+ /* Locate tag to see if processing should be skipped for this frame */
+ mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
+ if (mtag != NULL)
+ {
+ m_tag_unlink(m, mtag);
+ m_tag_free(mtag);
+ }
+
+ /*
+ * Handle incoming hook. This is connected to the
+ * input path of the interface, thus handling incoming frames.
+ */
if (pThis->u.s.input == hook)
- return ng_vboxnetflt_rcv_in(hook, item);
+ {
+ if (mtag != NULL || !fActive)
+ {
+ ether_demux(ifp, m);
+ return (0);
+ }
+ mtx_lock_spin(&pThis->u.s.inq.ifq_mtx);
+ _IF_ENQUEUE(&pThis->u.s.inq, m);
+ mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx);
+ taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskin);
+ }
+ /**
+ * Handle mbufs on the outgoing hook, frames going to the interface
+ */
else if (pThis->u.s.output == hook)
- return ng_vboxnetflt_rcv_out(hook, item);
+ {
+ if (mtag != NULL || !fActive)
+ return ether_output_frame(ifp, m);
+ mtx_lock_spin(&pThis->u.s.outq.ifq_mtx);
+ _IF_ENQUEUE(&pThis->u.s.outq, m);
+ mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx);
+ taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskout);
+ }
else
{
- NGI_GET_M(item, m);
- NG_FREE_ITEM(item);
+ m_freem(m);
}
return (0);
}
+static int ng_vboxnetflt_shutdown(node_p node)
+{
+ PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
+ bool fActive;
+
+ /* Prevent node shutdown if we're active */
+ fActive = ASMAtomicUoReadBool(&pThis->fActive);
+ if (fActive)
+ return (EBUSY);
+ NG_NODE_UNREF(node);
+ return (0);
+}
+
+static int ng_vboxnetflt_disconnect(hook_p hook)
+{
+ return (0);
+}
+
/**
- * Handle incoming hook. This is connected to the
- * input path of the interface, thus handling incoming frames.
+ * Input processing task, handles incoming frames
*/
-static int ng_vboxnetflt_rcv_in(hook_p hook, item_p item)
+static void vboxNetFltFreeBSDinput(void *arg, int pending)
{
+ PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg;
struct mbuf *m, *m0;
- struct m_tag *mtag;
- const node_p node = NG_HOOK_NODE(hook);
- PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
struct ifnet *ifp = pThis->u.s.ifp;
- bool fActive, fDropIt = false;
unsigned int cSegs = 0;
+ bool fDropIt = false, fActive;
PINTNETSG pSG;
- NGI_GET_M(item, m);
- NG_FREE_ITEM(item);
-
- fActive = ASMAtomicUoReadBool(&pThis->fActive);
- if (!fActive)
- goto out;
-
- mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
- if (mtag != NULL)
- {
- m_tag_unlink(m, mtag);
- m_tag_free(mtag);
- goto out;
- }
vboxNetFltRetain(pThis, true /* fBusy */);
-
- for (m0 = m; m0 != NULL; m0 = m0->m_next)
+ for (;;)
{
- if (m0->m_len > 0)
- cSegs++;
- }
+ mtx_lock_spin(&pThis->u.s.inq.ifq_mtx);
+ _IF_DEQUEUE(&pThis->u.s.inq, m);
+ mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx);
+ if (m == NULL)
+ break;
+ for (m0 = m; m0 != NULL; m0 = m0->m_next)
+ if (m0->m_len > 0)
+ cSegs++;
+
#ifdef PADD_RUNT_FRAMES_FROM_HOST
- if (m_length(m, NULL) < 60)
- cSegs++;
+ if (m_length(m, NULL) < 60)
+ cSegs++;
#endif
- /* Create a copy of the mbuf and hand it to the virtual switch */
- pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
- vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
- fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_WIRE);
- RTMemTmpFree(pSG);
+ /* Create a copy and deliver to the virtual switch */
+ pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
+ vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
+ fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
+ RTMemTmpFree(pSG);
+ if (fDropIt)
+ m_freem(m);
+ else
+ ether_demux(ifp, m);
+ }
vboxNetFltRelease(pThis, true /* fBusy */);
-
-out:
- /* Only deliver it to the host stack if the destination weren't a guest */
- if (fDropIt)
- {
- m_freem(m);
- return (0);
- }
- ether_demux(ifp, m);
- return (0);
}
/**
- * Handle mbufs on the outgoing hook, frames going to the interface
+ * Output processing task, handles outgoing frames
*/
-static int ng_vboxnetflt_rcv_out(hook_p hook, item_p item)
+static void vboxNetFltFreeBSDoutput(void *arg, int pending)
{
+ PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg;
struct mbuf *m, *m0;
- struct m_tag *mtag;
- const node_p node = NG_HOOK_NODE(hook);
- PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
struct ifnet *ifp = pThis->u.s.ifp;
unsigned int cSegs = 0;
bool fDropIt = false, fActive;
PINTNETSG pSG;
- NGI_GET_M(item, m);
- NG_FREE_ITEM(item);
-
- fActive = ASMAtomicUoReadBool(&pThis->fActive);
- if (!fActive)
- return ether_output_frame(ifp, m);
-
vboxNetFltRetain(pThis, true /* fBusy */);
- /* Pass directly to interface if the packet originated from us */
- mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
- if (mtag != NULL)
+ for (;;)
{
- m_tag_unlink(m, mtag);
- m_tag_free(mtag);
- goto out;
- }
+ mtx_lock_spin(&pThis->u.s.outq.ifq_mtx);
+ _IF_DEQUEUE(&pThis->u.s.outq, m);
+ mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx);
+ if (m == NULL)
+ break;
- for (m0 = m; m0 != NULL; m0 = m0->m_next)
- {
- if (m0->m_len > 0)
- cSegs++;
- }
+ for (m0 = m; m0 != NULL; m0 = m0->m_next)
+ if (m0->m_len > 0)
+ cSegs++;
#ifdef PADD_RUNT_FRAMES_FROM_HOST
- if (m_length(m, NULL) < 60)
- cSegs++;
+ if (m_length(m, NULL) < 60)
+ cSegs++;
#endif
- /* Create a copy and deliver to the virtual switch */
- pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
- vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
- fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
- RTMemTmpFree(pSG);
+ /* Create a copy and deliver to the virtual switch */
+ pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
+ vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
+ fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
+ RTMemTmpFree(pSG);
-out:
+ if (fDropIt)
+ m_freem(m);
+ else
+ ether_output_frame(ifp, m);
+ }
vboxNetFltRelease(pThis, true /* fBusy */);
- if (fDropIt)
- {
- m_freem(m);
- return (0);
- }
-
- return ether_output_frame(ifp, m);
}
-static int ng_vboxnetflt_shutdown(node_p node)
-{
- PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
- bool fActive;
-
- /* Prevent node shutdown if we're active */
- fActive = ASMAtomicUoReadBool(&pThis->fActive);
- if (fActive)
- return (EBUSY);
- NG_NODE_UNREF(node);
- return (0);
-}
-
-static int ng_vboxnetflt_disconnect(hook_p hook)
-{
- return (0);
-}
-
/**
* Called to deliver a frame to either the host, the wire or both.
*/
@@ -536,13 +542,23 @@
/* Create a new netgraph node for this instance */
if (ng_make_node_common(&ng_vboxnetflt_typestruct, &node) != 0)
- return VERR_INTERNAL_ERROR;
+ return VERR_INTERNAL_ERROR;
RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.ifp, ifp);
pThis->u.s.node = node;
bcopy(IF_LLADDR(ifp), &pThis->u.s.Mac, ETHER_ADDR_LEN);
ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
+ /* Initialize deferred input queue */
+ bzero(&pThis->u.s.inq, sizeof(struct ifqueue));
+ mtx_init(&pThis->u.s.inq.ifq_mtx, "vboxnetflt inq", NULL, MTX_SPIN);
+ TASK_INIT(&pThis->u.s.tskin, 0, vboxNetFltFreeBSDinput, pThis);
+
+ /* Initialize deferred output queue */
+ bzero(&pThis->u.s.outq, sizeof(struct ifqueue));
+ mtx_init(&pThis->u.s.outq.ifq_mtx, "vboxnetflt outq", NULL, MTX_SPIN);
+ TASK_INIT(&pThis->u.s.tskout, 0, vboxNetFltFreeBSDoutput, pThis);
+
RTSpinlockRelease(pThis->hSpinlock, &Tmp);
NG_NODE_SET_PRIVATE(node, pThis);
@@ -571,7 +587,10 @@
}
if (ifp0 != NULL)
+ {
+ vboxNetFltOsDeleteInstance(pThis);
vboxNetFltOsInitInstance(pThis, NULL);
+ }
return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
}
@@ -579,6 +598,12 @@
void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
{
+ taskqueue_drain(taskqueue_fast, &pThis->u.s.tskin);
+ taskqueue_drain(taskqueue_fast, &pThis->u.s.tskout);
+
+ mtx_destroy(&pThis->u.s.inq.ifq_mtx);
+ mtx_destroy(&pThis->u.s.outq.ifq_mtx);
+
if (pThis->u.s.node != NULL)
ng_rmnode_self(pThis->u.s.node);
pThis->u.s.node = NULL;

View File

@ -592,7 +592,7 @@ include/virtualbox/xpcom/xpcom-config.h
%%QT4%%@dirrmtry share/icons
%%QT4%%@dirrmtry share/applications
@dirrm lib/virtualbox/components
@dirrm lib/virtualbox/additions
%%GUESTADDITIONS%%@dirrm lib/virtualbox/additions
@dirrm lib/virtualbox
@cwd /
%%KMODDIR%%/vboxdrv.ko