Skip site navigation (1)Skip section navigation (2)
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>