From owner-freebsd-emulation Mon Nov 19 4:22:14 2001 Delivered-To: freebsd-emulation@freebsd.org Received: from pop3.psconsult.nl (ps226.psconsult.nl [193.67.147.226]) by hub.freebsd.org (Postfix) with ESMTP id E185737B417; Mon, 19 Nov 2001 04:20:32 -0800 (PST) Received: (from paul@localhost) by pop3.psconsult.nl (8.9.2/8.9.2) id NAA00117; Mon, 19 Nov 2001 13:17:42 +0100 (CET) (envelope-from paul) Date: Mon, 19 Nov 2001 13:17:42 +0100 From: Paul Schenkeveld To: Ian Dowse , Garance A Drosihn , Doug Ambrisko Cc: Dag-Erling Smorgrav , Takanori Saneto , emulation@FreeBSD.ORG, freebsd-emulation@FreeBSD.ORG Subject: Re: Linuxulator MFC and VMware/FYI, multiple vmwares is possible Message-ID: <20011119131742.A99773@psconsult.nl> References: <200111190522.fAJ5M5u80672@ambrisko.com> <200106121526.f5CFQsp46243@ambrisko.com> <200111161749.aa32146@salmon.maths.tcd.ie> <200111161749.aa32146@salmon.maths.tcd.ie> <20011118200951.A91961@psconsult.nl> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="7AUc2qLy4jB3hD7Z" X-Mailer: Mutt 1.0i In-Reply-To: <20011118200951.A91961@psconsult.nl> In-Reply-To: <200106121526.f5CFQsp46243@ambrisko.com> In-Reply-To: Sender: owner-freebsd-emulation@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org --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 #include #include #include #include +#if __FreeBSD_version >= 500014 +#include +#else #include +#endif #include #include #include @@ -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