git: 9front

Download patch

ref: a08ce962812370180d9f40172d350c637c41cfc4
parent: 200434baba1610a070122d3c59f95f3667654b43
parent: f916f6b77e7bc5716093850b66946ddbdc94c6a8
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Oct 19 09:11:26 EDT 2025

merge

--- a/sys/src/9/ip/devip.c
+++ b/sys/src/9/ip/devip.c
@@ -53,9 +53,8 @@
 
 static char network[] = "network";
 
-QLock	fslock;
-Fs	*ipfs[Nfs];	/* attached fs's */
-Queue	*qlog;
+static Fs	*ipfs[Nfs];	/* attached fs's */
+static Queue	*qlog;
 
 extern	void nullmediumlink(void);
 extern	void pktmediumlink(void);
@@ -290,6 +289,7 @@
 static Chan*
 ipattach(char* spec)
 {
+	static QLock lk;
 	Chan *c;
 	ulong dev;
 
@@ -297,7 +297,7 @@
 	if(dev >= Nfs)
 		error(Enodev);
 
-	qlock(&fslock);
+	qlock(&lk);
 	if(ipfs[dev] == nil){
 		extern void (*ipprotoinit[])(Fs*);
 		Fs *f;
@@ -310,9 +310,10 @@
 		for(i = 0; ipprotoinit[i]; i++)
 			ipprotoinit[i](f);
 		f->dev = dev;
+		coherence();
 		ipfs[dev] = f;
 	}
-	qunlock(&fslock);
+	qunlock(&lk);
 
 	c = devattach('I', spec);
 	mkqid(&c->qid, QID(0, 0, Qtopdir), 0, QTDIR);
--- a/sys/src/9/ip/ip.c
+++ b/sys/src/9/ip/ip.c
@@ -146,6 +146,23 @@
 	} else {
 		eh->vihl = IP_VER4|IP_HLEN4;
 		eh->tos = tos;
+
+		/* bypass for loopback */
+		if(r->type & Runi){
+			eh->ttl = ttl;
+			hnputs(eh->length, len);
+			hnputs(eh->id, incref(&ip->id4));
+			eh->frag[0] = 0;
+			eh->frag[1] = 0;
+			eh->cksum[0] = 0;
+			eh->cksum[1] = 0;
+			hnputs(eh->cksum, ipcsum(&eh->vihl));
+			bp->flag |= Bipck;
+			(*loopbackmedium.bwrite)(ifc, concatblock(bp), V4, gate, rh);
+			runlock(ifc);
+			poperror();
+			return 0;
+		}
 	}
 	eh->ttl = ttl;
 
@@ -160,7 +177,6 @@
 		eh->cksum[0] = 0;
 		eh->cksum[1] = 0;
 		hnputs(eh->cksum, ipcsum(&eh->vihl));
-
 		ipifcoput(ifc, bp, V4, gate, rh);
 		runlock(ifc);
 		poperror();
@@ -244,7 +260,6 @@
 		feh->cksum[0] = 0;
 		feh->cksum[1] = 0;
 		hnputs(feh->cksum, ipcsum(&feh->vihl));
-
 		ipifcoput(ifc, nb, V4, gate, rh);
 		ip->stats[FragCreates]++;
 	}
--- a/sys/src/9/ip/ip.h
+++ b/sys/src/9/ip/ip.h
@@ -391,6 +391,7 @@
 	uchar	mac[MAClen];	/* MAC address */
 
 	Iplifc	*lifc;		/* logical interfaces on this physical one */
+	Queue	*loopback;
 
 	ulong	in, out;	/* message statistics */
 	ulong	inerr, outerr;	/* ... */
@@ -719,6 +720,8 @@
  */
 extern Medium	ethermedium;
 extern Medium	nullmedium;
+extern Medium	unboundmedium;	/* same as nullmedium, to prevent unbind while bind or unbind is in progress */
+extern Medium	loopbackmedium;
 extern Medium	pktmedium;
 
 /*
--- a/sys/src/9/ip/ipifc.c
+++ b/sys/src/9/ip/ipifc.c
@@ -122,9 +122,6 @@
 	return *mp;
 }
 
-/* same as nullmedium, to prevent unbind while bind or unbind is in progress */
-extern Medium unboundmedium;
-
 /*
  *  attach a device (or pkt driver) to the interface.
  *  called with c locked
@@ -174,6 +171,8 @@
 		wunlock(ifc);
 		nexterror();
 	}
+	if(m != &loopbackmedium)
+		(*loopbackmedium.bind)(ifc, argc, argv);
 	(*m->bind)(ifc, argc, argv);
 	poperror();
 
@@ -466,6 +465,7 @@
 	c->sq = qopen(QMAX, 0, 0, 0);
 	if(c->rq == nil || c->wq == nil || c->sq == nil)
 		error(Enomem);
+
 	ifc = (Ipifc*)c->ptcl;
 	ifc->conv = c;
 	ifc->m = nil;
--- a/sys/src/9/ip/ipv6.c
+++ b/sys/src/9/ip/ipv6.c
@@ -101,6 +101,16 @@
 		eh->vcf[0] = IP_VER6;
 		eh->vcf[0] |= tos >> 4;
 		eh->vcf[1]  = tos << 4;
+
+		/* bypass for loopback */
+		if(r->type & Runi){
+			eh->ttl = ttl;
+			hnputs(eh->ploadlen, len - IP6HDR);
+			(*loopbackmedium.bwrite)(ifc, concatblock(bp), V6, gate, rh);
+			runlock(ifc);
+			poperror();
+			return 0;
+		}
 	}
 	eh->ttl = ttl;
 
--- a/sys/src/9/ip/loopbackmedium.c
+++ b/sys/src/9/ip/loopbackmedium.c
@@ -7,112 +7,62 @@
 
 #include "ip.h"
 
-enum
-{
-	Maxtu=	64*1024,
-};
-
-typedef struct LB LB;
-struct LB
-{
-	Proc	*readp;
-	Queue	*q;
-	Fs	*f;
-};
-
-static void loopbackread(void *a);
-
 static void
-loopbackbind(Ipifc *ifc, int, char**)
+readloopback(void *x)
 {
-	LB *lb;
+	Ipifc *ifc = (Ipifc*)x;
+	Fs *f = ifc->conv->p->f;
+	Block *bp;
 
-	lb = smalloc(sizeof(*lb));
-	lb->readp = (void*)-1;
-	lb->f = ifc->conv->p->f;
-	lb->q = qopen(1024*1024, Qmsg, nil, nil);
-	ifc->arg = lb;
-
-	kproc("loopbackread", loopbackread, ifc);
-
-}
-
-static void
-loopbackunbind(Ipifc *ifc)
-{
-	LB *lb = ifc->arg;
-
 	while(waserror())
 		;
-	/* wat for reader to start */
-	while(lb->readp == (void*)-1)
-		tsleep(&up->sleep, return0, 0, 300);
-		
-	if(lb->readp != nil)
-		postnote(lb->readp, 1, "unbind", 0);
-	poperror();
-
-	while(waserror())
-		;
-	/* wait for reader to die */
-	while(lb->readp != nil)
-		tsleep(&up->sleep, return0, 0, 300);
-	poperror();
-
-	/* clean up */
-	qfree(lb->q);
-	free(lb);
-}
-
-static void
-loopbackbwrite(Ipifc *ifc, Block *bp, int, uchar*, Routehint*)
-{
-	LB *lb;
-
-	lb = ifc->arg;
-	if(qpass(lb->q, bp) < 0)
-		ifc->outerr++;
-	ifc->out++;
-}
-
-static void
-loopbackread(void *a)
-{
-	Ipifc *ifc;
-	Block *bp;
-	LB *lb;
-
-	ifc = a;
-	lb = ifc->arg;
-	lb->readp = up;	/* hide identity under a rock for unbind */
-	if(!waserror())
-	while((bp = qbread(lb->q, Maxtu)) != nil){
+	while((bp = qbread(ifc->loopback, IP_MAX)) != nil){
 		rlock(ifc);
 		if(waserror()){
 			runlock(ifc);
 			continue;
 		}
-		ifc->in++;
 		if(ifc->lifc == nil)
 			freeb(bp);
-		else
-			ipiput4(lb->f, ifc, bp);
+		else {
+			ifc->in++;
+			ipiput4(f, ifc, bp);
+		}
 		runlock(ifc);
 		poperror();
 	}
-	lb->readp = nil;
 	pexit("hangup", 1);
 }
 
+static void
+loopbackbind(Ipifc *ifc, int, char**)
+{
+	if(ifc->loopback != nil)
+		return;
+
+	ifc->loopback = qopen(1024*1024, Qmsg, 0, 0);
+	if(ifc->loopback == nil)
+		error(Enomem);
+	kproc("loopbackread", readloopback, ifc);
+
+}
+
+static void
+loopbackbwrite(Ipifc *ifc, Block *bp, int, uchar*, Routehint*)
+{
+	if(qpass(ifc->loopback, bp) < 0)
+		ifc->outerr++;
+	ifc->out++;
+}
+
 Medium loopbackmedium =
 {
 .hsize=		0,
 .mintu=		0,
-.maxtu=		Maxtu,
+.maxtu=		IP_MAX,
 .maclen=	0,
 .name=		"loopback",
 .bind=		loopbackbind,
-.unbind=	loopbackunbind,
 .bwrite=	loopbackbwrite,
 };
 
--- a/sys/src/9/ip/tcp.c
+++ b/sys/src/9/ip/tcp.c
@@ -200,6 +200,7 @@
 typedef struct Tcpctl Tcpctl;
 struct Tcpctl
 {
+	Conv	*bypass;		/* The other when bypassing */
 	uchar	state;			/* Connection state */
 	uchar	type;			/* Listening or active connection */
 	uchar	code;			/* Icmp code */
@@ -251,6 +252,7 @@
 	ulong	rttseq;			/* Round trip sequence */
 	int	srtt;			/* Smoothed round trip */
 	int	mdev;			/* Mean deviation of round trip */
+
 	union {
 		Tcp4hdr	tcp4hdr;
 		Tcp6hdr	tcp6hdr;
@@ -412,6 +414,10 @@
 		qclose(s->rq);
 		qclose(s->wq);
 		qclose(s->eq);
+		if(tcb->bypass != nil){
+			tcb->bypass = nil;
+			qsetbypass(s->wq, nil);
+		}
 		break;
 
 	case Close_wait:		/* Remote closes */
@@ -523,8 +529,14 @@
 	case Syn_sent:
 		localclose(c, nil);
 		break;
-	case Syn_received:
 	case Established:
+		if(tcb->bypass != nil){
+			qhangup(tcb->bypass->rq, nil);
+			localclose(c, nil);
+			break;
+		}
+		/* wet floor */
+	case Syn_received:
 		tcb->flgcnt++;
 		tcb->snd.nxt++;
 		tcpsetstate(c, Finwait1);
@@ -547,9 +559,12 @@
 
 	qlock(s);
 	switch(tcb->state) {
+	case Established:
+		if(tcb->bypass != nil)
+			break;
+		/* wet floor */
 	case Syn_sent:
 	case Syn_received:
-	case Established:
 	case Close_wait:
 		/*
 		 * Push data
@@ -623,7 +638,7 @@
 	Tcpctl *tcb = (Tcpctl*)s->ptcl;
 
 	qlock(s);
-	if(tcb->state != Closed){
+	if(tcb->state != Closed && tcb->bypass == nil){
 		tcb->flags |= FORCE;
 		tcpoutput(s);
 	}
@@ -1325,7 +1340,7 @@
 {
 	Tcpctl *tcb = (Tcpctl*)s->ptcl;
 
-	if(ipcmp(s->raddr, IPnoaddr) != 0 && tcb->state != Closed) {
+	if(ipcmp(s->raddr, IPnoaddr) != 0 && tcb->state != Closed && tcb->bypass == nil) {
 		Block *bp;
 		Tcp seg;
 
@@ -1565,7 +1580,60 @@
 	tcb->mdev = rtt<<(LOGDGAIN-1);
 }
 
+static void
+tcpbypass(void *arg, Block *b)
+{
+	Conv *c = (Conv*)arg;
+	Tcpctl *tcb = (Tcpctl*)c->ptcl;
+	Conv *o = tcb->bypass;
+
+	if(o == nil || ((Tcpctl*)o->ptcl)->bypass != c){
+		freeblist(b);
+		return;
+	}
+	qbwrite(o->rq, b);
+}
+
 /*
+ *  splice two local tcp conversations together,
+ *  having the wq directly bypass into the other
+ *  ends rq.
+ *
+ *  both new, old and proto are locked.
+ */
+static void
+tcpsplice(Conv *new, Conv *old)
+{
+	Tcppriv *tpriv;
+	Tcpctl *ntcb, *otcb;
+
+	ntcb = (Tcpctl*)new->ptcl;
+	otcb = (Tcpctl*)old->ptcl;
+
+	if(otcb->state != Established)
+		return;
+
+	ntcb->bypass = old;
+	otcb->bypass = new;
+
+	qsetlimit(new->rq, conf.pipeqsize);
+	qsetlimit(old->rq, conf.pipeqsize);
+	qsetbypass(new->wq, tcpbypass);
+	qsetbypass(old->wq, tcpbypass);
+
+	/* stop timers and drump resequencing queue */
+	tpriv = (Tcppriv*)new->p->priv;
+	tcphalt(tpriv, &ntcb->timer);
+	tcphalt(tpriv, &otcb->timer);
+	tcphalt(tpriv, &ntcb->acktimer);
+	tcphalt(tpriv, &otcb->acktimer);
+	tcphalt(tpriv, &ntcb->katimer);
+	tcphalt(tpriv, &otcb->katimer);
+	dumpreseq(ntcb);
+	dumpreseq(otcb);
+}
+
+/*
  *  come here when we finally get an ACK to our SYN-ACK.
  *  lookup call in limbo.  if found, create a new conversation
  *
@@ -1575,6 +1643,7 @@
 tcpincoming(Conv *s, Tcp *seg, uchar *src, uchar *dst, int version)
 {
 	Tcppriv *tpriv;
+	Route *rp;
 	Limbo *lp, **l;
 	Conv *new;
 	Tcpctl *tcb;
@@ -1630,7 +1699,8 @@
 	tcpsynackrtt(tcb);
 
 	/* the same as what we sent in SYN,ACK */
-	tcb->mss = tcpmtu(v6lookup(s->p->f, src, dst, new), &tcb->scale, version);
+	rp = v6lookup(s->p->f, src, dst, new);
+	tcb->mss = tcpmtu(rp, &tcb->scale, version);
 
 	tcpsetmss(new, lp->mss);
 	tcpsetscale(new, lp->ws);
@@ -1666,8 +1736,23 @@
 		panic("tcpincoming: version %d", new->ipversion);
 	}
 
+	qlock(new);
 	tcpsetstate(new, Established);
 	iphtadd(&tpriv->ht, new);
+	if(rp != nil && (rp->type & Runi) != 0){
+		/* see if we can find the local conversation and splice them together */
+		Iphash *iph = iphtlook(&tpriv->ht, new->laddr, new->lport, new->raddr, new->rport);
+		if(iph != nil && iph->trans == 0){
+			Conv *old = iphconv(iph);
+			if(old != new){
+				qlock(old);
+				tcpsplice(new, old);
+				qunlock(old);
+			}
+		}
+	}
+	qunlock(new);
+
 	return new;
 }
 
@@ -2144,6 +2229,9 @@
 			tcpsetstate(s, Established);
 			break;
 		case Established:
+			if(tcb->bypass != nil)
+				goto raise;
+			/* wet floor */
 		case Close_wait:
 		case Finwait2:
 			update(s, &seg);
@@ -2513,7 +2601,7 @@
 	Tcpctl *tcb = (Tcpctl*)s->ptcl;
 
 	qlock(s);
-	if(tcb->state != Closed){
+	if(tcb->state != Closed && tcb->bypass == nil){
 		if(++(tcb->kato) > MAX_KAT) {
 			localclose(s, Etimedout);
 		} else if(tcpsendka(s) < 0) {
@@ -2536,6 +2624,9 @@
 
 	if(tcb->state != Established)
 		return "connection must be in Establised state";
+
+	if(tcb->bypass != nil)
+		return nil;
 
 	x = DEF_KAT;
 	if(n > 1){
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -288,6 +288,7 @@
 Block*		qbread(Queue*, int);
 long		qbwrite(Queue*, Block*);
 Queue*		qbypass(void (*)(void*, Block*), void*);
+void		qsetbypass(Queue*, void (*)(void*, Block*));
 int		qcanread(Queue*);
 void		qclose(Queue*);
 int		qconsume(Queue*, void*, int);
--- a/sys/src/9/port/qio.c
+++ b/sys/src/9/port/qio.c
@@ -759,6 +759,24 @@
 	return q;
 }
 
+void
+qsetbypass(Queue *q, void (*bypass)(void*, Block*))
+{
+	Block *b;
+
+	ilock(q);
+	if(bypass != nil){
+		while((b = qremove(q)) != nil){
+			iunlock(q);
+			(*bypass)(q->arg, b);
+			ilock(q);
+		}
+		q->state |= Qstarve;
+	}
+	q->bypass = bypass;
+	iunlock_consumer(q);
+}
+
 static int
 notempty(void *a)
 {
--