Date: Mon, 19 Nov 2001 13:17:42 +0100 From: Paul Schenkeveld <paul@psconsult.nl> To: Ian Dowse <iedowse@maths.tcd.ie>, Garance A Drosihn <drosih@rpi.edu>, Doug Ambrisko <ambrisko@ambrisko.com> Cc: Dag-Erling Smorgrav <des@ofug.org>, Takanori Saneto <sanewo@ba2.so-net.ne.jp>, emulation@FreeBSD.ORG, freebsd-emulation@FreeBSD.ORG Subject: Re: Linuxulator MFC and VMware/FYI, multiple vmwares is possible Message-ID: <20011119131742.A99773@psconsult.nl> In-Reply-To: <p05101006b81e0fd1fae9@[128.113.24.47]> References: <p05101006b81e0fd1fae9@[128.113.24.47]> <200111190522.fAJ5M5u80672@ambrisko.com> <200106121526.f5CFQsp46243@ambrisko.com> <p05101006b81e0fd1fae9@[128.113.24.47]> <200111161749.aa32146@salmon.maths.tcd.ie> <p05101007b81e1ff6c3c7@[128.113.24.47]> <xzpofm2od5b.fsf@flood.ping.uio.no> <200111161749.aa32146@salmon.maths.tcd.ie> <20011118200951.A91961@psconsult.nl>
next in thread | previous in thread | raw e-mail | index | archive | help
--7AUc2qLy4jB3hD7Z
Content-Type: text/plain; charset=us-ascii
Hi all,
As I had a great time with vmware2-2.0.3-799 and multiple
simultaneous sessions, I decided to see if I could retrofit those
patches into vmware2-2.0.4-1142.
Vladimirs vmmon-freebsd-0.99-0 and vmnet-freebsd-0.22 changes
do not apply cleanly to vmware2-2.0.4-1142 so I found out
which parts were needed to enable multiple simultanous sessions.
Attached are vmmon.diff, the part of vmmon-freebsd-0.99-0 that
enables multiple sessions (to be applied to vmware 2.0.4-1142
AFTER the vmmon-freebsd-0.98 patches) and tap.diff, a patch that
I picked up early this year which was needed for bridging with
multiple sessions.
BTW, I run 4.4-STABLE as of Sun Nov 18, 2001.
To use all this I did the following:
# cd /usr; cvs co ports/emulators/vmware2
# cd ports/emulators/vmware2
# make patch # to get the official patches
# for the latest vmware release
# patch -p1 < vmmon.diff # to get multi-session in vmmon
# make install
# cd /usr/src
# patch -p0 < tap.diff # to get multi-session bridged vmnet
# patch -p0 < linux_ioctl.diff # from Ian Dowse, earlier in this list
# make -j8 buildworld
# make installworld
Then reboot and see vmware 2.0.4-1142 work with multiple sessions.
Does anyone see something I overlooked?
If not and if everyone is happy with these patches, how can we get
this back into the port?
Regards,
Paul Schenkeveld, Consultant
PSconsult ICT Services BV
Houten, The Netherlands
--7AUc2qLy4jB3hD7Z
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="vmmon.diff"
diff -u vmware2/work/vmmon-only/freebsd/driver.c vmware2-multi/work/vmmon-only/freebsd/driver.c
--- vmware2/work/vmmon-only/freebsd/driver.c Thu Jun 29 14:06:18 2000
+++ vmware2-multi/work/vmmon-only/freebsd/driver.c Sun Nov 18 21:29:56 2001
@@ -34,18 +34,21 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $vmFreeBSD: vmware/vmmon-only/freebsd/driver.c,v 1.26 2000/06/29 12:06:18 vsilyaev Exp $
+ * $vmFreeBSD: vmware/vmmon-only/freebsd/driver.c,v 1.26 2001/01/28 15:22:27 vsilyaev Exp $
*
*/
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/conf.h>
+#if __FreeBSD_version >= 500014
+#include <sys/selinfo.h>
+#else
#include <sys/select.h>
+#endif
#include <sys/fcntl.h>
#include <sys/malloc.h>
#include <sys/proc.h>
@@ -142,7 +145,7 @@
/* maj */ CDEV_MAJOR,
/* dump */ nodump,
/* psize */ nopsize,
- /* flags */ 0,
+ /* flags */ D_TRACKCLOSE,
/* bmaj */ -1
};
@@ -296,6 +299,33 @@
#endif
DEV_MODULE(vmmon, vmmon_modeevent, 0);
+
+#if !DRV_MULTIPLE_INSTANCES
+#define DRV_INITINSTANCE() if (dev->si_drv1) return EBUSY
+#define DRV_GET_INSTANCE(inst) inst = (VMFreeBSD *) dev->si_drv1
+#define DRV_DEREFERENCE(inst) dev->si_drv1=NULL;
+#define DRV_REFERENCE(inst) dev->si_drv1 = inst;
+#error "Single Instance!"
+#else
+#warn "Multiple Instances!"
+LIST_HEAD(drv_list, VMFreeBSD);
+
+#define DRV_INITINSTANCE() struct drv_list *drvrs; if (!dev->si_drv1) {\
+ drvrs = malloc(sizeof (*drvrs), M_DEVBUF, M_WAITOK); \
+ LIST_INIT(drvrs); dev->si_drv1=drvrs; \
+ } else { drvrs=dev->si_drv1; }
+
+#define DRV_REFERENCE(inst) inst->owner = p;LIST_INSERT_HEAD(drvrs, inst, list)
+
+#define DRV_DEREFERENCE(inst) LIST_REMOVE(inst, list);\
+ if (LIST_EMPTY(drvrs)) {free(drvrs, M_DEVBUF);dev->si_drv1=NULL;}
+
+#define DRV_GET_INSTANCE(inst) struct drv_list *drvrs=dev->si_drv1; \
+ LIST_FOREACH(inst, drvrs, list) \
+ if ((inst->owner==p) || (inst->owner==p->p_pptr)) break; \
+ if(!inst) {printf("vmmon: Can't found instance for %d\n", p->p_pid); return ENODEV;}
+
+#endif
/*
*----------------------------------------------------------------------
*
@@ -316,9 +346,8 @@
VMFreeBSD *vmFreeBSD;
VMDriver *vm;
uint32 flags;
-
- if (dev->si_drv1)
- return EBUSY;
+
+ DRV_INITINSTANCE();
if ((oflag & (FREAD|FWRITE)) == FREAD) {
#ifdef VMX86_DEVEL
@@ -355,8 +384,7 @@
RESTORE_FLAGS(flags);
vmFreeBSD->vm = vm;
- dev->si_drv1 = vmFreeBSD;
-
+ DRV_REFERENCE(vmFreeBSD);
FreeBSD_DriverQueue(vmFreeBSD);
@@ -393,7 +421,9 @@
static int
FreeBSD_Driver_Close(dev_t dev, int fflag, int devtype, struct proc *p)
{
- VMFreeBSD *vmFreeBSD = (VMFreeBSD *) dev->si_drv1;
+ VMFreeBSD *vmFreeBSD;
+
+ DRV_GET_INSTANCE(vmFreeBSD);
#ifdef SUPPORT_LINUXVMWARE
VMWare_SetVTracer(0);
@@ -424,8 +454,8 @@
untimeout(FreeBSD_DriverSelectTimeout, vmFreeBSD, vmFreeBSD->thandle);
}
+ DRV_DEREFERENCE(vmFreeBSD);
free(vmFreeBSD, M_DEVBUF);
- dev->si_drv1 = NULL;
vmmon_ref_count--;
return 0;
}
@@ -447,9 +477,11 @@
{
int revents = 0;
- VMFreeBSD *vmFreeBSD = (VMFreeBSD *) dev->si_drv1;
+ VMFreeBSD *vmFreeBSD;
intrmask_t s;
+ DRV_GET_INSTANCE(vmFreeBSD);
+
s=splhigh();
HostIF_GlobalVMLock(11); /* protect access to vmFreeBSD */
if (vmFreeBSD->flags.tfired) {
@@ -528,13 +560,15 @@
FreeBSD_Driver_Ioctl( dev_t dev, u_long cmd, caddr_t parg, int mode,
struct proc *p)
{
- VMFreeBSD *vmFreeBSD = (VMFreeBSD *) dev->si_drv1;
- VMDriver *vm = vmFreeBSD->vm;
+ VMFreeBSD *vmFreeBSD;
+ VMDriver *vm;
int retval = 0;
int err;
InitBlock initParams;
u_long arg=*(u_long *)parg;
+ DRV_GET_INSTANCE(vmFreeBSD);
+ vm = vmFreeBSD->vm;
#ifdef SUPPORT_LINUXVMWARE
VMWare_SetVTracer(VTrace_Set);
diff -u vmware2/work/vmmon-only/freebsd/driver.h vmware2-multi/work/vmmon-only/freebsd/driver.h
--- vmware2/work/vmmon-only/freebsd/driver.h Sun Jan 23 23:29:19 2000
+++ vmware2-multi/work/vmmon-only/freebsd/driver.h Sun Nov 18 21:29:56 2001
@@ -15,6 +15,8 @@
#define POLL_TRACE 0
+#define DRV_MULTIPLE_INSTANCES 1
+
typedef struct VMFreeBSD {
struct VMFreeBSD *next;
struct VMDriver *vm;
@@ -38,6 +40,10 @@
unsigned char pendingPassthroughIRQs[NUM_PASSTHROUGH_IRQS];
#endif
+#if DRV_MULTIPLE_INSTANCES
+ struct proc *owner;
+ LIST_ENTRY(VMFreeBSD) list;
+#endif
} VMFreeBSD;
#define DEVICE_BUFFER_SIZE 32
--7AUc2qLy4jB3hD7Z
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="tap.diff"
--- /sys/net/if_tap.c.orig Thu Jul 27 09:57:05 2000
+++ /sys/net/if_tap.c Sun Jan 28 20:48:13 2001
@@ -107,7 +107,7 @@
/* dev major */ CDEV_MAJOR,
/* dump */ nodump,
/* psize */ nopsize,
- /* flags */ 0,
+ /* flags */ D_TRACKCLOSE,
/* bmaj */ -1
};
@@ -120,6 +120,36 @@
SYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
DEV_MODULE(if_tap, tapmodevent, NULL);
+#if !DRV_MULTIPLE_INSTANCES
+#define DRV_INITINSTANCE() if (tp->tap_flags & TAP_OPEN) return (EBUSY); \
+ else {tn=&tp->node; tp->tap_flags |= TAP_OPEN;}
+
+#define DRV_GET_INSTANCE(inst, p) inst = &tp->node;
+#define DRV_DEREFERENCE(inst) tp->tap_flags &= ~TAP_OPEN
+#define DRV_REFERENCE(inst)
+#else
+
+#define DRV_INITINSTANCE() if ( !(tp->tap_flags & TAP_VMNET) && !LIST_EMPTY(&tp->nodes) ) return (EBUSY); \
+ MALLOC(tn, struct tap_node *, sizeof(*tn), M_TAP, M_WAITOK|M_ZERO); \
+ tn->ifq.ifq_maxlen = ifqmaxlen; \
+ tp->tap_flags |= TAP_OPEN;
+
+#define DRV_REFERENCE(inst) LIST_INSERT_HEAD(&tp->nodes, inst, list); \
+ inst->owner = p; tp->n_nodes++;
+
+#define DRV_DEREFERENCE(inst) LIST_REMOVE(inst, list); tp->n_nodes--; \
+ free(inst, M_TAP); \
+ if (LIST_EMPTY(&tp->nodes)) tp->tap_flags &= ~TAP_OPEN
+
+#define DRV_GET_INSTANCE(inst, p) \
+ if ( tp->tap_flags & TAP_VMNET) {\
+ LIST_FOREACH(inst, &tp->nodes, list) \
+ if ((inst->owner==p) || (inst->owner==p->p_pptr)) break; \
+ } else inst = LIST_FIRST(&tp->nodes); \
+ if (!inst) {printf("tap: Can't found instance for %d\n", p->p_pid); return ENODEV;}
+
+#endif
+
/*
* tapmodevent
*
@@ -161,7 +191,7 @@
splx(s);
if (ifp != NULL) {
- struct tap_softc *tp = ifp->if_softc;
+ struct tap_softc *tp = ifp->if_softc;
TAPDEBUG("detaching %s%d. minor = %#x, " \
"taplastunit = %d\n",
@@ -199,7 +229,7 @@
dev_t dev;
{
struct ifnet *ifp = NULL;
- struct tap_softc *tp = NULL;
+ struct tap_softc *tp = NULL;
unsigned short macaddr_hi;
int unit, s;
char *name = NULL;
@@ -252,6 +282,9 @@
tp->tap_flags |= TAP_INITED;
+#if DRV_MULTIPLE_INSTANCES
+ LIST_INIT(&tp->nodes);
+#endif
TAPDEBUG("interface %s%d created. minor = %#x\n",
ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
} /* tapcreate */
@@ -270,6 +303,7 @@
struct proc *p;
{
struct tap_softc *tp = NULL;
+ struct tap_node *tn = NULL;
int error;
if ((error = suser(p)) != 0)
@@ -281,15 +315,15 @@
tp = dev->si_drv1;
}
- if (tp->tap_flags & TAP_OPEN)
- return (EBUSY);
+ DRV_INITINSTANCE();
- bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
+ bcopy(tp->arpcom.ac_enaddr, tn->ether_addr, sizeof(tn->ether_addr));
tp->tap_pid = p->p_pid;
- tp->tap_flags |= TAP_OPEN;
+ DRV_REFERENCE(tn);
taprefcnt ++;
+
TAPDEBUG("%s%d is open. minor = %#x, refcnt = %d, taplastunit = %d\n",
tp->tap_if.if_name, tp->tap_if.if_unit,
minor(tp->tap_dev), taprefcnt, taplastunit);
@@ -314,9 +348,11 @@
struct tap_softc *tp = dev->si_drv1;
struct ifnet *ifp = &tp->tap_if;
struct mbuf *m = NULL;
+ struct tap_node *tn;
- /* junk all pending output */
+ DRV_GET_INSTANCE(tn, p);
+ /* junk all pending output */
s = splimp();
do {
IF_DEQUEUE(&ifp->if_snd, m);
@@ -355,11 +391,23 @@
}
splx(s);
}
+#if DRV_MULTIPLE_INSTANCES
+ if (tp->tap_flags & TAP_VMNET) {
+ /* Junk all pending packets in node queue */
+ s = splimp();
+ do {
+ IF_DEQUEUE(&tn->ifq, m);
+ if (m != NULL)
+ m_freem(m);
+ } while (m != NULL);
+ splx(s);
+}
+#endif
+
+ funsetown(tn->tap_sigio);
+ selwakeup(&tn->tap_rsel);
- funsetown(tp->tap_sigio);
- selwakeup(&tp->tap_rsel);
-
- tp->tap_flags &= ~TAP_OPEN;
+ DRV_DEREFERENCE(tn);
tp->tap_pid = 0;
taprefcnt --;
@@ -448,6 +496,22 @@
return (0);
} /* tapifioctl */
+#define ETHER_EQUAL(a,b) (((const u_int32_t *)(a))[0] == ((const u_int32_t *)(b))[0] && \
+ ((const u_int16_t *)(a))[2] == ((const u_int16_t *)(b))[2])
+
+static void
+node_new_packet(struct tap_softc *tp, struct tap_node *tn)
+{
+ TAPDEBUG("new packet for %p\n", tn);
+ if (tn->tapn_flags & TAP_RWAIT) {
+ tn->tapn_flags &= ~TAP_RWAIT;
+ wakeup((caddr_t)tn);
+ }
+ if ((tn->tapn_flags & TAP_ASYNC) && (tn->tap_sigio != NULL))
+ pgsigio(tn->tap_sigio, SIGIO, 0);
+
+ selwakeup(&tn->tap_rsel);
+}
/*
* tapifstart
@@ -460,6 +524,7 @@
{
struct tap_softc *tp = ifp->if_softc;
int s;
+ struct mbuf *m;
TAPDEBUG("%s%d starting, minor = %#x\n",
ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
@@ -471,7 +536,6 @@
if (((tp->tap_flags & TAP_VMNET) == 0) &&
((tp->tap_flags & TAP_READY) != TAP_READY)) {
- struct mbuf *m = NULL;
TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n",
ifp->if_name, ifp->if_unit,
@@ -491,20 +555,76 @@
s = splimp();
ifp->if_flags |= IFF_OACTIVE;
-
- if (ifp->if_snd.ifq_len != 0) {
- if (tp->tap_flags & TAP_RWAIT) {
- tp->tap_flags &= ~TAP_RWAIT;
- wakeup((caddr_t)tp);
- }
-
- if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL))
- pgsigio(tp->tap_sigio, SIGIO, 0);
-
- selwakeup(&tp->tap_rsel);
- ifp->if_opackets ++; /* obytes are counted in ether_output */
+ if (ifp->if_snd.ifq_len == 0) {
+ goto done;
}
+ ifp->if_opackets ++; /* obytes are counted in ether_output */
+#if !DRV_MULTIPLE_INSTANCES
+ tn = &tp->node;
+ node_new_packet(tp, &tp->node);
+#else
+ if (!(tp->tap_flags & TAP_VMNET)) {
+ node_new_packet(tp, LIST_FIRST(&tp->nodes));
+ goto done;
+ }
+ if (LIST_EMPTY(&tp->nodes))
+ goto done;
+
+ for(;;) {
+ struct ether_header *eh;
+ struct tap_node *tn;
+
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (!m) break;
+ /* Sanity check packet and pull up header */
+ if (m->m_pkthdr.len < ETHER_HDR_LEN) {
+ m_freem(m);
+ continue;
+ }
+ if (m->m_len < ETHER_HDR_LEN && !(m = m_pullup(m, ETHER_HDR_LEN))) {
+ m_freem(m);
+ continue;
+ }
+ eh = mtod(m, struct ether_header *);
+ LIST_FOREACH(tn, &tp->nodes, list) {
+ if (ETHER_EQUAL(tn->ether_addr, eh->ether_dhost)) break;
+ }
+ if (tn) { /* unicast */
+ if (IF_QFULL(&tn->ifq)) {
+ IF_DROP(&tn->ifq);
+ m_freem(m);
+ } else {
+ TAPDEBUG("start u %6D->%6D (%d)\n", eh->ether_shost, ":", eh->ether_dhost, ":", m->m_len);
+ IF_ENQUEUE(&tn->ifq, m);
+ node_new_packet(tp, tn);
+ }
+ goto done;
+ } else { /* unknown or [broad/multi]cast */
+ struct mbuf *mdup;
+ int i=0;
+ LIST_FOREACH(tn, &tp->nodes, list) {
+ if (++i == tp->n_nodes) { /* last node, don't dup */
+ mdup = m;
+ } else {
+ mdup = m_dup(m, M_NOWAIT); /* XXX m_copypacket() */
+ if (!mdup) {
+ continue;
+ }
+ }
+ if (IF_QFULL(&tn->ifq)) {
+ IF_DROP(&tn->ifq);
+ m_freem(mdup);
+ } else {
+ TAPDEBUG("start m %6D->%6D (%d)\n", eh->ether_shost, ":", eh->ether_dhost, ":", mdup->m_len);
+ IF_ENQUEUE(&tn->ifq, mdup);
+ node_new_packet(tp, tn);
+ }
+ } /* LIST_FOREACH */
+ } /* unicast/broadcast */
+ } /* foreach packet */
+#endif
+done:
ifp->if_flags &= ~IFF_OACTIVE;
splx(s);
} /* tapifstart */
@@ -527,6 +647,9 @@
struct ifnet *ifp = &tp->tap_if;
struct tapinfo *tapp = NULL;
int s;
+ struct tap_node *tn;
+
+ DRV_GET_INSTANCE(tn, p);
switch (cmd) {
case TAPSIFINFO:
@@ -559,9 +682,9 @@
case FIOASYNC:
s = splimp();
if (*(int *)data)
- tp->tap_flags |= TAP_ASYNC;
+ tn->tapn_flags |= TAP_ASYNC;
else
- tp->tap_flags &= ~TAP_ASYNC;
+ tn->tapn_flags &= ~TAP_ASYNC;
splx(s);
break;
@@ -579,19 +702,19 @@
break;
case FIOSETOWN:
- return (fsetown(*(int *)data, &tp->tap_sigio));
+ return (fsetown(*(int *)data, &tn->tap_sigio));
case FIOGETOWN:
- *(int *)data = fgetown(tp->tap_sigio);
+ *(int *)data = fgetown(tn->tap_sigio);
return (0);
/* this is deprecated, FIOSETOWN should be used instead */
case TIOCSPGRP:
- return (fsetown(-(*(int *)data), &tp->tap_sigio));
+ return (fsetown(-(*(int *)data), &tn->tap_sigio));
/* this is deprecated, FIOGETOWN should be used instead */
case TIOCGPGRP:
- *(int *)data = -fgetown(tp->tap_sigio);
+ *(int *)data = -fgetown(tn->tap_sigio);
return (0);
/* VMware/VMnet port ioctl's */
@@ -614,11 +737,11 @@
case OSIOCGIFADDR: /* get MAC address of the remote side */
case SIOCGIFADDR:
- bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
+ bcopy(tn->ether_addr, data, sizeof(tn->ether_addr));
break;
case SIOCSIFADDR: /* set MAC address of the remote side */
- bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
+ bcopy(data, tn->ether_addr, sizeof(tn->ether_addr));
break;
default:
@@ -644,6 +767,10 @@
struct ifnet *ifp = &tp->tap_if;
struct mbuf *m = NULL, *m0 = NULL;
int error = 0, len, s;
+ struct tap_node *tn;
+ struct ifqueue *ifq;
+
+ DRV_GET_INSTANCE(tn, uio->uio_procp);
TAPDEBUG("%s%d reading, minor = %#x\n",
ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
@@ -655,21 +782,30 @@
return (EHOSTDOWN);
}
+#if !DRV_MULTIPLE_INSTANCES
+ ifq = &ifp->if_snd;
+#else
+ if (!(tp->tap_flags & TAP_VMNET)) {
+ ifq = &ifp->if_snd;
+ } else {
+ ifq = &tn->ifq;
+ }
+#endif
- tp->tap_flags &= ~TAP_RWAIT;
+ tn->tapn_flags &= ~TAP_RWAIT;
/* sleep until we get a packet */
do {
s = splimp();
- IF_DEQUEUE(&ifp->if_snd, m0);
+ IF_DEQUEUE(ifq, m0);
splx(s);
if (m0 == NULL) {
if (flag & IO_NDELAY)
return (EWOULDBLOCK);
- tp->tap_flags |= TAP_RWAIT;
- error = tsleep((caddr_t)tp,PCATCH|(PZERO+1),"taprd",0);
+ tn->tapn_flags |= TAP_RWAIT;
+ error = tsleep((caddr_t)tn,PCATCH|(PZERO+1),"taprd",0);
if (error)
return (error);
}
@@ -679,6 +815,13 @@
if (ifp->if_bpf != NULL)
bpf_mtap(ifp, m0);
+
+ {
+ struct ether_header *eh;
+ eh = mtod(m0, struct ether_header *);
+ TAPDEBUG("tap read %6D->%6D (%d)\n", eh->ether_shost, ":", eh->ether_dhost, ":", m0->m_len);
+ }
+
/* xfer packet to user space */
while ((m0 != NULL) && (uio->uio_resid > 0) && (error == 0)) {
len = min(uio->uio_resid, m0->m_len);
@@ -716,6 +859,9 @@
struct mbuf *top = NULL, **mp = NULL, *m = NULL;
struct ether_header *eh = NULL;
int error = 0, tlen, mlen;
+ struct tap_node *tn;
+
+ DRV_GET_INSTANCE(tn, uio->uio_procp);
TAPDEBUG("%s%d writting, minor = %#x\n",
ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
@@ -763,7 +909,8 @@
top->m_pkthdr.len = tlen;
top->m_pkthdr.rcvif = ifp;
-
+
+
/*
* Ethernet bridge and bpf are handled in ether_input
*
@@ -771,9 +918,45 @@
*/
eh = mtod(top, struct ether_header *);
+#if DRV_MULTIPLE_INSTANCES
+ if (tp->tap_flags & TAP_VMNET) {
+ struct tap_node *tn_dest;
+ LIST_FOREACH(tn_dest, &tp->nodes, list) {
+ if (ETHER_EQUAL(tn_dest->ether_addr, eh->ether_dhost)) break;
+ }
+ if (tn_dest) { /* unicast */
+ if (tn_dest == tn) goto done;
+ if (IF_QFULL(&tn_dest->ifq)) {
+ IF_DROP(&tn_dest->ifq);
+ } else {
+ TAPDEBUG("write u %6D->%6D (%d)\n", eh->ether_shost, ":", eh->ether_dhost, ":", top->m_len);
+ IF_ENQUEUE(&tn_dest->ifq, top);
+ node_new_packet(tp, tn_dest);
+ /* XXX Check promisc mode and deliver packet to local side also */
+ goto done;
+ }
+ } else { /* unknown or [broad/multi]cast */
+ LIST_FOREACH(tn_dest, &tp->nodes, list) {
+ if (tn==tn_dest) continue;
+ if (IF_QFULL(&tn_dest->ifq)) {
+ IF_DROP(&tn_dest->ifq);
+ continue;
+ }
+ m = m_dup(top, M_NOWAIT); /* XXX m_copypacket() */
+ if (!m) {
+ continue;
+ }
+ TAPDEBUG("write m %6D->%6D (%d)\n", eh->ether_shost, ":", eh->ether_dhost, ":", m->m_len);
+ IF_ENQUEUE(&tn_dest->ifq, m);
+ node_new_packet(tp, tn_dest);
+ } /* LIST_FOREACH */
+ } /* uni/broad cast */
+ } /* if VMNET */
+#endif
m_adj(top, sizeof(struct ether_header));
ether_input(ifp, eh, top);
ifp->if_ipackets ++; /* ibytes are counted in ether_input */
+done:
return (0);
} /* tapwrite */
@@ -795,24 +978,40 @@
struct tap_softc *tp = dev->si_drv1;
struct ifnet *ifp = &tp->tap_if;
int s, revents = 0;
+ struct tap_node *tn;
+ struct ifqueue *ifq;
+
+ DRV_GET_INSTANCE(tn, p);
+#if 0
TAPDEBUG("%s%d polling, minor = %#x\n",
ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
+#endif
+#if !DRV_MULTIPLE_INSTANCES
+ ifq = &ifp->if_snd;
+#else
+ if (!(tp->tap_flags & TAP_VMNET)) {
+ ifq = &ifp->if_snd;
+ } else {
+ ifq = &tn->ifq;
+ }
+#endif
s = splimp();
if (events & (POLLIN | POLLRDNORM)) {
- if (ifp->if_snd.ifq_len > 0) {
+ if (ifq->ifq_len > 0) {
TAPDEBUG("%s%d have data in queue. len = %d, " \
"minor = %#x\n", ifp->if_name, ifp->if_unit,
- ifp->if_snd.ifq_len, minor(tp->tap_dev));
+ ifq->ifq_len, minor(tp->tap_dev));
revents |= (events & (POLLIN | POLLRDNORM));
}
else {
+#if 0
TAPDEBUG("%s%d waiting for data, minor = %#x\n",
ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
-
- selrecord(p, &tp->tap_rsel);
+#endif
+ selrecord(p, &tn->tap_rsel);
}
}
--- /sys/net/if_tapvar.h.orig Thu Jul 27 09:57:05 2000
+++ /sys/net/if_tapvar.h Sun Jan 28 16:19:39 2001
@@ -41,6 +41,22 @@
#ifndef _NET_IF_TAPVAR_H_
#define _NET_IF_TAPVAR_H_
+#define DRV_MULTIPLE_INSTANCES 1
+
+struct tap_node {
+ u_int8_t ether_addr[ETHER_ADDR_LEN]; /* ether addr of the remote side */
+ struct sigio *tap_sigio; /* information for async I/O */
+ struct selinfo tap_rsel; /* read select */
+ u_short tapn_flags; /* misc flags */
+#define TAP_RWAIT (1 << 2)
+#define TAP_ASYNC (1 << 3)
+#if DRV_MULTIPLE_INSTANCES
+ struct ifqueue ifq; /* packets received for this node */
+ struct proc *owner; /* process who open this node */
+ LIST_ENTRY(tap_node) list;
+#endif
+};
+
struct tap_softc {
struct arpcom arpcom; /* ethernet common data */
#define tap_if arpcom.ac_if
@@ -49,16 +65,16 @@
u_short tap_flags; /* misc flags */
#define TAP_OPEN (1 << 0)
#define TAP_INITED (1 << 1)
-#define TAP_RWAIT (1 << 2)
-#define TAP_ASYNC (1 << 3)
#define TAP_READY (TAP_OPEN|TAP_INITED)
#define TAP_VMNET (1 << 4)
+ pid_t tap_pid; /* PID of process to open */
+#if DRV_MULTIPLE_INSTANCES
+ int n_nodes;
+ LIST_HEAD(, tap_node) nodes;
+#else
+ struct tap_node node;
+#endif
+};
- u_int8_t ether_addr[ETHER_ADDR_LEN]; /* ether addr of the remote side */
-
- pid_t tap_pid; /* PID of process to open */
- struct sigio *tap_sigio; /* information for async I/O */
- struct selinfo tap_rsel; /* read select */
-};
#endif /* !_NET_IF_TAPVAR_H_ */
--7AUc2qLy4jB3hD7Z--
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-emulation" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20011119131742.A99773>
