code: plan9front

Download patch

ref: 6ebb8b9e357944cc29ae3fafc0900ee3e325ed39
parent: 55c3138c640967ae82b21feb4c33acb9edcbc75b
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Oct 3 11:58:58 EDT 2021

devip: use better hashipa() macro, use RWlock for arp cache

--- a/sys/src/9/ip/arp.c
+++ b/sys/src/9/ip/arp.c
@@ -33,7 +33,7 @@
  */
 struct Arp
 {
-	QLock;
+	RWlock;
 	Fs	*f;
 	Arpent	*hash[NHASH];
 	Arpent	cache[NCACHE];
@@ -45,7 +45,8 @@
 
 char *Ebadarp = "bad arp";
 
-#define haship(s) ((s)[IPaddrlen-1]%NHASH)
+/* quick hash for ip addresses */
+#define hashipa(a) (((a)[IPaddrlen-2] + (a)[IPaddrlen-1])%NHASH)
 
 static void 	rxmitproc(void*);
 
@@ -95,7 +96,7 @@
 	Block *bp;
 
 	/* take out of current chain */
-	for(l = &arp->hash[haship(a->ip)]; *l != nil; l = &((*l)->hash)){
+	for(l = &arp->hash[hashipa(a->ip)]; *l != nil; l = &((*l)->hash)){
 		if(*l == a){
 			*l = a->hash;
 			break;
@@ -127,9 +128,6 @@
 
 	a->utime = 0;
 	a->ctime = 0;
-
-	memset(a->ip, 0, sizeof(a->ip));
-	memset(a->mac, 0, sizeof(a->mac));
 }
 
 /*
@@ -158,7 +156,7 @@
 	a->ifcid = ifc->ifcid;
 
 	/* insert into new chain */
-	l = &arp->hash[haship(ip)];
+	l = &arp->hash[hashipa(ip)];
 	a->hash = *l;
 	*l = a;
 
@@ -165,7 +163,18 @@
 	return a;
 }
 
+static Arpent*
+arplookup(Arp *arp, Ipifc *ifc, uchar *ip)
+{
+	Arpent *a;
 
+	for(a = arp->hash[hashipa(ip)]; a != nil; a = a->hash){
+		if(a->ifc == ifc && a->ifcid == ifc->ifcid && ipcmp(ip, a->ip) == 0)
+			return a;
+	}
+	return nil;
+}
+
 /*
  *  fill in the media address if we have it.  Otherwise return an
  *  Arpent that represents the state of the address resolution FSM
@@ -175,44 +184,39 @@
 Arpent*
 arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac)
 {
-	Arpent *a;
 	uchar v6ip[IPaddrlen];
+	Arpent *a;
 
 	if(version == V4){
 		v4tov6(v6ip, ip);
 		ip = v6ip;
 	}
-
-	qlock(arp);
-	for(a = arp->hash[haship(ip)]; a != nil; a = a->hash){
-		if(a->ifc == ifc && a->ifcid == ifc->ifcid && ipcmp(ip, a->ip) == 0)
-			break;
+	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){
+			runlock(arp);
+			return nil;
+		}
 	}
-	if(a == nil){
+	runlock(arp);
+	wlock(arp);
+	if((a = arplookup(arp, ifc, ip)) == nil)
 		a = newarpent(arp, ip, ifc);
-		a->state = AWAIT;
-	}
+	a->state = AWAIT;
 	a->utime = NOW;
-	if(a->state == AWAIT){
-		if(bp != nil){
-			bp->list = nil; 
-			if(a->hold == nil)
-				a->hold = bp;
-			else
-				a->last->list = bp;
-			a->last = bp;
-		}
-		return a;		/* return with arp qlocked */
-	}
+	if(bp != nil){
+		/* needs to be a single block */
+		assert(bp->list == nil);
 
-	memmove(mac, a->mac, ifc->m->maclen);
-
-	/* remove old entries */
-	if(NOW - a->ctime > 15*60*1000)
-		cleanarpent(arp, a);
-
-	qunlock(arp);
-	return nil;
+		if(a->hold == nil)
+			a->hold = bp;
+		else
+			a->last->list = bp;
+		a->last = bp;
+	}
+	return a;		/* return with arp locked */
 }
 
 /*
@@ -226,9 +230,6 @@
 	Arpent **l;
 	Block *bp;
 
-	/* try to keep it around for a second more */
-	a->ctime = NOW;
-
 	/* remove all but the last message */
 	while((bp = a->hold) != nil){
 		if(bp == a->last)
@@ -237,6 +238,9 @@
 		freeblist(bp);
 	}
 
+	/* try to keep it around for a second more */
+	a->ctime = a->utime = NOW;
+
 	/* put on end of re-transmit / timeout chain */
 	for(l = rxmtunchain(arp, a); *l != nil; l = &(*l)->nextrxt)
 		;
@@ -245,7 +249,7 @@
 	if(l == &arp->rxmt[0] || l == &arp->rxmt[1])
 		wakeup(&arp->rxmtq);
 
-	qunlock(arp);
+	wunlock(arp);
 }
 
 /*
@@ -254,7 +258,7 @@
 void
 arprelease(Arp *arp, Arpent*)
 {
-	qunlock(arp);
+	wunlock(arp);
 }
 
 
@@ -274,11 +278,11 @@
 		rxmtunchain(arp, a);
 		a->rxtsrem = 0;
 	}
-	a->state = AOK;
-	a->ctime = a->utime = NOW;
 	bp = a->hold;
 	a->hold = a->last = nil;
-	qunlock(arp);
+	a->ctime = a->utime = NOW;
+	a->state = AOK;
+	wunlock(arp);
 
 	return bp;
 }
@@ -313,37 +317,29 @@
 		return -1;
 
 	arp = fs->arp;
-	qlock(arp);
-	for(a = arp->hash[haship(ip)]; a != nil; a = a->hash){
-		if(a->ifc != ifc || a->ifcid != ifc->ifcid)
-			continue;
-		if(ipcmp(a->ip, ip) == 0){
-			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;
-				if(waserror()){
-					freeblistchain(next);
-					break;
-				}
-				ipifcoput(ifc, bp, version, ip);
-				poperror();
-			}
-			return 1;
-		}
-	}
 
-	if(refresh == 0){
+	wlock(arp);
+	if((a = arplookup(arp, ifc, ip)) == nil){
+		if(refresh){
+			wunlock(arp);
+			return 0;
+		}
 		a = newarpent(arp, ip, ifc);
-		a->state = AOK;
-		a->ctime = a->utime = NOW;
-		memmove(a->mac, mac, n);
 	}
-	qunlock(arp);
-
-	return refresh == 0;
+	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;
+		if(waserror()){
+			freeblistchain(next);
+			break;
+		}
+		ipifcoput(ifc, bp, version, ip);
+		poperror();
+	}
+	return 1;
 }
 
 int
@@ -370,10 +366,8 @@
 
 	n = getfields(buf, f, nelem(f), 1, " ");
 	if(strcmp(f[0], "flush") == 0){
-		qlock(arp);
+		wlock(arp);
 		for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
-			memset(a->ip, 0, sizeof(a->ip));
-			memset(a->mac, 0, sizeof(a->mac));
 			a->hash = nil;
 			a->nextrxt = nil;
 			a->ifc = nil;
@@ -389,7 +383,7 @@
 		freeblistchain(arp->dropf);
 		arp->dropf = arp->dropl = nil;
 		arp->rxmt[0] = arp->rxmt[1] = nil;
-		qunlock(arp);
+		wunlock(arp);
 	} else if(strcmp(f[0], "add") == 0){
 		switch(n){
 		default:
@@ -436,13 +430,13 @@
 			error(Ebadarg);
 		if (parseip(ip, f[1]) == -1)
 			error(Ebadip);
-		qlock(arp);
-		for(a = arp->hash[haship(ip)]; a != nil; a = x){
+		wlock(arp);
+		for(a = arp->hash[hashipa(ip)]; a != nil; a = x){
 			x = a->hash;
 			if(ipcmp(ip, a->ip) == 0)
 				cleanarpent(arp, a);
 		}
-		qunlock(arp);
+		wunlock(arp);
 	} else
 		error(Ebadarp);
 
@@ -472,17 +466,17 @@
 			continue;
 
 		rlock(ifc);
-		qlock(arp);
-		state = arpstate[a->state];
+		rlock(arp);
 		ipmove(ip, a->ip);
-		if(ifc->m == nil || a->ifcid != ifc->ifcid || !ipv6local(ifc, ia, 0, ip)){
-			qunlock(arp);
+		if(ifc->m == nil || a->state == 0 || a->ifc != ifc || a->ifcid != ifc->ifcid || !ipv6local(ifc, ia, 0, ip)){
+			runlock(arp);
 			runlock(ifc);
 			continue;
 		}
 		mname = ifc->m->name;
+		state = arpstate[a->state];
 		convmac(mac, a->mac, ifc->m->maclen);
-		qunlock(arp);
+		runlock(arp);
 		runlock(ifc);
 
 		n = snprint(up->genbuf, sizeof up->genbuf,
@@ -538,7 +532,7 @@
 	Block *bp;
 	Ipifc *ifc;
 
-	qlock(arp);
+	wlock(arp);
 
 	/* retransmit ipv6 solicitations */
 	while((a = arp->rxmt[0]) != nil && NOW - a->ctime > 3*RETRANS_TIMER/4){
@@ -546,7 +540,8 @@
 			if(a->ifcid == ifc->ifcid){
 				ndpsendsol(arp->f, ifc, a);	/* unlocks arp */
 				runlock(ifc);
-				qlock(arp);
+
+				wlock(arp);
 				continue;
 			}
 			runlock(ifc);
@@ -561,7 +556,7 @@
 	bp = arp->dropf;
 	arp->dropf = arp->dropl = nil;
 
-	qunlock(arp);
+	wunlock(arp);
 
 	return bp;
 }
--- a/sys/src/9/ip/ethermedium.c
+++ b/sys/src/9/ip/ethermedium.c
@@ -267,7 +267,7 @@
 		bp = multicastarp(er->f, a, ifc->m, mac);
 		if(bp == nil){
 			/* don't do anything if it's been less than a second since the last */
-			if(NOW - a->ctime < RETRANS_TIMER){
+			if(a->utime - a->ctime < RETRANS_TIMER){
 				arprelease(er->f->arp, a);
 				return;
 			}
@@ -284,6 +284,9 @@
 			return;
 		}
 	}
+
+	/* need to have single block */
+	assert(bp->list == nil);
 
 	/* make it a single block with space for the ether header */
 	bp = padblock(bp, ifc->m->hsize);
--- a/sys/src/9/ip/ipifc.c
+++ b/sys/src/9/ip/ipifc.c
@@ -53,7 +53,7 @@
 };
 
 /* quick hash for ip addresses */
-#define hashipa(a) ( ( ((a)[IPaddrlen-2]<<8) | (a)[IPaddrlen-1] )%NHASH )
+#define hashipa(a) (((a)[IPaddrlen-2] + (a)[IPaddrlen-1])%NHASH)
 
 static char tifc[] = "ifc ";