code: plan9front

Download patch

ref: 1a6324970d4cb0f0508caa3a685355d500709f1a
parent: d280f411f68cebc5aac71ce8b7cbcfb5b22f1a7c
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Oct 9 14:26:16 EDT 2021

devip: cache arp entry in Routehint

Instead of having to do an arp hash table lookup for each
outgoing ip packet, forward the Routehint pointer to the
medium's bwrite() function and let it cache the arp entry
pointer.

This avoids route and arp hash table lookups for tcp, il
and connection oriented udp.

It also allows us to avoid multiple route and arp table
lookups for the retransmits once an arp/neighbour solicitation
response arrives.

--- a/sys/src/9/ip/arp.c
+++ b/sys/src/9/ip/arp.c
@@ -19,6 +19,8 @@
 
 	AOK		= 1,
 	AWAIT		= 2,
+
+	MAXAGE_TIMER	= 15*60*1000,
 };
 
 char *arpstate[] =
@@ -182,7 +184,7 @@
  *  waiting for ip->mac to be resolved.
  */
 Arpent*
-arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac)
+arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac, Routehint *rh)
 {
 	uchar v6ip[IPaddrlen];
 	Arpent *a;
@@ -191,15 +193,32 @@
 		v4tov6(v6ip, ip);
 		ip = v6ip;
 	}
+
+	if(rh != nil
+	&& (a = rh->a) != nil
+	&& a->state == AOK
+	&& a->ifc == ifc
+	&& a->ifcid == ifc->ifcid
+	&& ipcmp(ip, a->ip) == 0){
+		memmove(mac, a->mac, ifc->m->maclen);
+		a->utime = NOW;
+		if(a->utime - a->ctime < MAXAGE_TIMER)
+			return nil;
+	}
+
 	rlock(arp);
 	if((a = arplookup(arp, ifc, ip)) != nil && a->state == AOK){
 		memmove(mac, a->mac, ifc->m->maclen);
 		a->utime = NOW;
-		if(a->utime - a->ctime < 15*60*1000){
+		if(a->utime - a->ctime < MAXAGE_TIMER){
+			if(rh != nil)
+				rh->a = a;
 			runlock(arp);
 			return nil;
 		}
 	}
+	if(rh != nil)
+		rh->a = nil;
 	runlock(arp);
 	wlock(arp);
 	if((a = arplookup(arp, ifc, ip)) == nil)
@@ -269,11 +288,11 @@
  * called with arp locked
  */
 Block*
-arpresolve(Arp *arp, Arpent *a, Medium *type, uchar *mac)
+arpresolve(Arp *arp, Arpent *a, uchar *mac, Routehint *rh)
 {
 	Block *bp;
 
-	memmove(a->mac, mac, type->maclen);
+	memmove(a->mac, mac, a->ifc->m->maclen);
 	if(a->state == AWAIT) {
 		rxmtunchain(arp, a);
 		a->rxtsrem = 0;
@@ -282,6 +301,8 @@
 	a->hold = a->last = nil;
 	a->ctime = a->utime = NOW;
 	a->state = AOK;
+	if(rh != nil)
+		rh->a = a;
 	wunlock(arp);
 
 	return bp;
@@ -290,6 +311,7 @@
 int
 arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, uchar *ia, Ipifc *ifc, int refresh)
 {
+	Routehint rh;
 	uchar v6ip[IPaddrlen];
 	Block *bp, *next;
 	Arpent *a;
@@ -299,14 +321,16 @@
 	if(ifc->m == nil || ifc->m->maclen != n || ifc->m->maclen == 0)
 		return -1;
 
+	rh.r = nil;
+	rh.a = nil;
 	switch(version){
 	case V4:
-		r = v4lookup(fs, ip, ia, nil);
+		r = v4lookup(fs, ip, ia, &rh);
 		v4tov6(v6ip, ip);
 		ip = v6ip;
 		break;
 	case V6:
-		r = v6lookup(fs, ip, ia, nil);
+		r = v6lookup(fs, ip, ia, &rh);
 		break;
 	default:
 		panic("arpenter: version %d", version);
@@ -326,9 +350,9 @@
 		}
 		a = newarpent(arp, ip, ifc);
 	}
+	bp = arpresolve(arp, a, mac, &rh);	/* unlocks arp */
 	if(version == V4)
 		ip += IPv4off;
-	bp = arpresolve(arp, a, ifc->m, mac);	/* unlocks arp */
 	for(; bp != nil; bp = next){
 		next = bp->list;
 		bp->list = nil;
@@ -336,7 +360,7 @@
 			freeblistchain(next);
 			break;
 		}
-		ipifcoput(ifc, bp, version, ip);
+		ipifcoput(ifc, bp, version, ip, &rh);
 		poperror();
 	}
 	return 1;
@@ -496,8 +520,9 @@
 }
 
 void
-ndpsendsol(Fs *f, Ipifc *ifc, Arpent *a)
+ndpsendsol(Fs *f, Arpent *a)
 {
+	Ipifc *ifc = a->ifc;
 	uchar targ[IPaddrlen], src[IPaddrlen];
 
 	if(a->rxtsrem == 0)
@@ -538,7 +563,7 @@
 	while((a = arp->rxmt[0]) != nil && NOW - a->ctime > 3*RETRANS_TIMER/4){
 		if(a->rxtsrem > 0 && (ifc = a->ifc) != nil && canrlock(ifc)){
 			if(a->ifcid == ifc->ifcid){
-				ndpsendsol(arp->f, ifc, a);	/* unlocks arp */
+				ndpsendsol(arp->f, a);	/* unlocks arp */
 				runlock(ifc);
 
 				wlock(arp);
--- a/sys/src/9/ip/devip.c
+++ b/sys/src/9/ip/devip.c
@@ -1332,6 +1332,7 @@
 	c->state = Idle;
 	ipmove(c->laddr, IPnoaddr);
 	ipmove(c->raddr, IPnoaddr);
+	c->a = nil;
 	c->r = nil;
 	c->rgen = 0;
 	c->lport = 0;
--- a/sys/src/9/ip/ethermedium.c
+++ b/sys/src/9/ip/ethermedium.c
@@ -21,12 +21,12 @@
 static void	etherread6(void *a);
 static void	etherbind(Ipifc *ifc, int argc, char **argv);
 static void	etherunbind(Ipifc *ifc);
-static void	etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
+static void	etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip, Routehint *rh);
 static void	etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia);
 static void	etherremmulti(Ipifc *ifc, uchar *a, uchar *ia);
 static void	etherareg(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *ip);
-static Block*	multicastarp(Fs *f, Arpent *a, Medium*, uchar *mac);
-static void	sendarpreq(Ipifc *ifc, Arpent *a);
+static Block*	multicastarp(Fs *f, Arpent *a, uchar *mac, Routehint *rh);
+static void	sendarpreq(Fs *f, Arpent *a);
 static int	multicastea(uchar *ea, uchar *ip);
 static void	recvarpproc(void*);
 static void	etherpref2addr(uchar *pref, uchar *ea);
@@ -253,7 +253,7 @@
  *  called by ipoput with a single block to write with ifc rlock'd
  */
 static void
-etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
+etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip, Routehint *rh)
 {
 	Etherhdr *eh;
 	Arpent *a;
@@ -261,22 +261,22 @@
 	Etherrock *er = ifc->arg;
 
 	/* get mac address of destination */
-	a = arpget(er->f->arp, bp, version, ifc, ip, mac);
+	a = arpget(er->f->arp, bp, version, ifc, ip, mac, rh);
 	if(a != nil){
 		/* check for broadcast or multicast */
-		bp = multicastarp(er->f, a, ifc->m, mac);
+		bp = multicastarp(er->f, a, mac, rh);
 		if(bp == nil){
 			/* don't do anything if it's been less than a second since the last */
 			if(a->utime - a->ctime < RETRANS_TIMER){
-				arprelease(er->f->arp, a);
+				arprelease(er->f->arp, a);	/* unlocks arp */
 				return;
 			}
 			switch(version){
 			case V4:
-				sendarpreq(ifc, a);		/* unlocks arp */
+				sendarpreq(er->f, a);	/* unlocks arp */
 				break;
 			case V6:
-				ndpsendsol(er->f, ifc, a);	/* unlocks arp */
+				ndpsendsol(er->f, a);	/* unlocks arp */
 				break;
 			default:
 				panic("etherbwrite: version %d", version);
@@ -440,16 +440,17 @@
  *  (only v4, v6 uses the neighbor discovery, rfc1970)
  */
 static void
-sendarpreq(Ipifc *ifc, Arpent *a)
+sendarpreq(Fs *f, Arpent *a)
 {
 	int n;
 	Block *bp;
 	Etherarp *e;
+	Ipifc *ifc = a->ifc;
 	Etherrock *er = ifc->arg;
 	uchar targ[IPv4addrlen], src[IPv4addrlen];
 
 	memmove(targ, a->ip+IPv4off, IPv4addrlen);
-	arpcontinue(er->f->arp, a);
+	arpcontinue(f->arp, a);
 
 	if(!ipv4local(ifc, src, 0, targ))
 		return;
@@ -668,12 +669,12 @@
  *  IP address.
  */
 static Block*
-multicastarp(Fs *f, Arpent *a, Medium *medium, uchar *mac)
+multicastarp(Fs *f, Arpent *a, uchar *mac, Routehint *rh)
 {
 	/* is it broadcast? */
 	if(ipforme(f, a->ip) == Rbcast){
-		memset(mac, 0xff, medium->maclen);
-		return arpresolve(f->arp, a, medium, mac);
+		memset(mac, 0xff, a->ifc->m->maclen);
+		return arpresolve(f->arp, a, mac, rh);
 	}
 
 	/* if multicast, fill in mac */
@@ -680,7 +681,7 @@
 	switch(multicastea(mac, a->ip)){
 	case V4:
 	case V6:
-		return arpresolve(f->arp, a, medium, mac);
+		return arpresolve(f->arp, a, mac, rh);
 	}
 
 	/* let arp take care of it */
--- a/sys/src/9/ip/ip.c
+++ b/sys/src/9/ip/ip.c
@@ -153,7 +153,7 @@
 		eh->cksum[1] = 0;
 		hnputs(eh->cksum, ipcsum(&eh->vihl));
 
-		ipifcoput(ifc, bp, V4, gate);
+		ipifcoput(ifc, bp, V4, gate, rh);
 		runlock(ifc);
 		poperror();
 		return 0;
@@ -237,7 +237,7 @@
 		feh->cksum[1] = 0;
 		hnputs(feh->cksum, ipcsum(&feh->vihl));
 
-		ipifcoput(ifc, nb, V4, gate);
+		ipifcoput(ifc, nb, V4, gate, rh);
 		ip->stats[FragCreates]++;
 	}
 	ip->stats[FragOKs]++;
@@ -308,8 +308,8 @@
 	/* route */
 	v4tov6(v6dst, h->dst);
 	if(!ipforme(f, v6dst)) {
-		Route *r;
 		Routehint rh;
+		Route *r;
 		Ipifc *nifc;
 
 		if(!ip->iprouting)
@@ -317,6 +317,7 @@
 
 		/* don't forward to source's network */
 		rh.r = nil;
+		rh.a = nil;
 		r = v4lookup(f, h->dst, h->src, &rh);
 		if(r == nil || (nifc = r->ifc) == nil
 		|| (nifc == ifc && !ifc->reflect)){
--- a/sys/src/9/ip/ip.h
+++ b/sys/src/9/ip/ip.h
@@ -168,6 +168,7 @@
 {
 	Route	*r;			/* last route used */
 	ulong	rgen;			/* routetable generation for *r */
+	Arpent	*a;			/* last arp entry used */
 };
 
 /*
@@ -232,7 +233,7 @@
 	int	maclen;		/* mac address length  */
 	void	(*bind)(Ipifc*, int, char**);
 	void	(*unbind)(Ipifc*);
-	void	(*bwrite)(Ipifc *ifc, Block *b, int version, uchar *ip);
+	void	(*bwrite)(Ipifc *ifc, Block *b, int version, uchar *ip, Routehint *rh);
 
 	/* for arming interfaces to receive multicast */
 	void	(*addmulti)(Ipifc *ifc, uchar *a, uchar *ia);
@@ -565,8 +566,8 @@
 
 extern void	addroute(Fs *f, uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag);
 extern void	remroute(Fs *f, uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag);
-extern Route*	v4lookup(Fs *f, uchar *a, uchar *s, Routehint *h);
-extern Route*	v6lookup(Fs *f, uchar *a, uchar *s, Routehint *h);
+extern Route*	v4lookup(Fs *f, uchar *a, uchar *s, Routehint *rh);
+extern Route*	v6lookup(Fs *f, uchar *a, uchar *s, Routehint *rh);
 extern Route*	v4source(Fs *f, uchar *a, uchar *s);
 extern Route*	v6source(Fs *f, uchar *a, uchar *s);
 extern long	routeread(Fs *f, char*, ulong, int);
@@ -611,12 +612,12 @@
 extern void	arpinit(Fs*);
 extern int	arpread(Arp*, char*, ulong, int);
 extern int	arpwrite(Fs*, char*, int);
-extern Arpent*	arpget(Arp*, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *h);
+extern Arpent*	arpget(Arp*, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac, Routehint *rh);
 extern void	arprelease(Arp*, Arpent *a);
 extern void	arpcontinue(Arp*, Arpent *a);
-extern Block*	arpresolve(Arp*, Arpent *a, Medium *type, uchar *mac);
+extern Block*	arpresolve(Arp*, Arpent *a, uchar *mac, Routehint *rh);
 extern int	arpenter(Fs*, int version, uchar *ip, uchar *mac, int n, uchar *ia, Ipifc *ifc, int refresh);
-extern void	ndpsendsol(Fs*, Ipifc*, Arpent*);
+extern void	ndpsendsol(Fs*, Arpent*);
 
 /*
  * ipaux.c
@@ -661,7 +662,7 @@
  */
 extern Medium*	ipfindmedium(char *name);
 extern void	addipmedium(Medium *med);
-extern void	ipifcoput(Ipifc *ifc, Block *bp, int version, uchar *ip);
+extern void	ipifcoput(Ipifc *ifc, Block *bp, int version, uchar *ip, Routehint *rh);
 extern int	ipforme(Fs*, uchar *addr);
 extern int	ipismulticast(uchar *ip);
 extern Ipifc*	findipifc(Fs*, uchar *local, uchar *remote, int type);
--- a/sys/src/9/ip/ipifc.c
+++ b/sys/src/9/ip/ipifc.c
@@ -347,7 +347,7 @@
 }
 
 void
-ipifcoput(Ipifc *ifc, Block *bp, int version, uchar *ip)
+ipifcoput(Ipifc *ifc, Block *bp, int version, uchar *ip, Routehint *rh)
 {
 	if(ifc->speed){
 		ulong now = MACHP(0)->ticks;
@@ -363,7 +363,7 @@
 	}
 	bp = concatblock(bp);
 	ifc->load += BLEN(bp);
-	ifc->m->bwrite(ifc, bp, version, ip);
+	ifc->m->bwrite(ifc, bp, version, ip, rh);
 }
 
 
--- a/sys/src/9/ip/ipv6.c
+++ b/sys/src/9/ip/ipv6.c
@@ -99,7 +99,7 @@
 	medialen = ifc->maxtu - ifc->m->hsize;
 	if(len <= medialen) {
 		hnputs(eh->ploadlen, len - IP6HDR);
-		ipifcoput(ifc, bp, V6, gate);
+		ipifcoput(ifc, bp, V6, gate, rh);
 		runlock(ifc);
 		poperror();
 		return 0;
@@ -195,7 +195,7 @@
 			if(xp->rp == xp->wp)
 				xp = xp->next;
 		}
-		ipifcoput(ifc, nb, V6, gate);
+		ipifcoput(ifc, nb, V6, gate, rh);
 		ip->stats[FragCreates]++;
 	}
 	ip->stats[FragOKs]++;
@@ -252,8 +252,8 @@
 
 	/* route */
 	if(!ipforme(f, h->dst)) {
-		Route *r;
 		Routehint rh;
+		Route *r;
 		Ipifc *nifc;
 
 		if(!ip->iprouting)
@@ -268,6 +268,7 @@
 			
 		/* don't forward to source's network */
 		rh.r = nil;
+		rh.a = nil;
 		r  = v6lookup(f, h->dst, h->src, &rh);
 		if(r == nil || (nifc = r->ifc) == nil || (r->type & Rv4) != 0
 		|| (nifc == ifc && !ifc->reflect)){
--- a/sys/src/9/ip/loopbackmedium.c
+++ b/sys/src/9/ip/loopbackmedium.c
@@ -71,7 +71,7 @@
 }
 
 static void
-loopbackbwrite(Ipifc *ifc, Block *bp, int, uchar*)
+loopbackbwrite(Ipifc *ifc, Block *bp, int, uchar*, Routehint*)
 {
 	LB *lb;
 
--- a/sys/src/9/ip/netdevmedium.c
+++ b/sys/src/9/ip/netdevmedium.c
@@ -9,7 +9,7 @@
 
 static void	netdevbind(Ipifc *ifc, int argc, char **argv);
 static void	netdevunbind(Ipifc *ifc);
-static void	netdevbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
+static void	netdevbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip, Routehint*);
 static void	netdevread(void *a);
 
 typedef struct	Netdevrock Netdevrock;
@@ -99,7 +99,7 @@
  *  called by ipoput with a single block to write
  */
 static void
-netdevbwrite(Ipifc *ifc, Block *bp, int, uchar*)
+netdevbwrite(Ipifc *ifc, Block *bp, int, uchar*, Routehint*)
 {
 	Netdevrock *er = ifc->arg;
 
--- a/sys/src/9/ip/nullmedium.c
+++ b/sys/src/9/ip/nullmedium.c
@@ -19,7 +19,7 @@
 }
 
 static void
-nullbwrite(Ipifc*, Block *bp, int, uchar*)
+nullbwrite(Ipifc*, Block *bp, int, uchar*, Routehint*)
 {
 	freeb(bp);
 	error("nullbwrite");
--- a/sys/src/9/ip/pktmedium.c
+++ b/sys/src/9/ip/pktmedium.c
@@ -10,7 +10,7 @@
 
 static void	pktbind(Ipifc*, int, char**);
 static void	pktunbind(Ipifc*);
-static void	pktbwrite(Ipifc*, Block*, int, uchar*);
+static void	pktbwrite(Ipifc*, Block*, int, uchar*, Routehint*);
 static void	pktin(Fs*, Ipifc*, Block*);
 
 Medium pktmedium =
@@ -49,7 +49,7 @@
  *  called by ipoput with a single packet to write
  */
 static void
-pktbwrite(Ipifc *ifc, Block *bp, int, uchar*)
+pktbwrite(Ipifc *ifc, Block *bp, int, uchar*, Routehint*)
 {
 	/* enqueue onto the conversation's rq */
 	if(ifc->conv->snoopers.ref > 0)