ref: 48b49361d8830d535e6dd3e696d58f856b2cd95f
parent: a54d1cd95e19dc6685c1a6a5c22d6fdf6f0068eb
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Mon Nov 7 17:43:37 EST 2016
devbridge: various bugfixes and improvements from charles forsyth
--- a/sys/src/9/port/devbridge.c
+++ b/sys/src/9/port/devbridge.c
@@ -39,6 +39,7 @@
CacheLook= 5, // how many cache entries to examine
CacheSize= (CacheHash+CacheLook-1),
CacheTimeout= 5*60, // timeout for cache entry in seconds
+ MaxMTU= IP_MAX, // allow for jumbo frames and large UDP
TcpMssMax = 1300, // max desirable Tcp MSS value
TunnelMtu = 1400,
@@ -109,9 +110,9 @@
struct Port
{
+ Ref;
int id;
Bridge *bridge;
- int ref;
int closed;
Chan *data[2]; // channel to data
@@ -291,7 +292,7 @@
USED(off);
switch(TYPE(c->qid)) {
default:
- error(Eperm);
+ error(Egreg);
case Qtopdir:
case Qbridgedir:
case Qportdir:
@@ -298,8 +299,14 @@
return devdirread(c, a, n, 0, 0, bridgegen);
case Qlog:
return logread(b, a, off, n);
+ case Qlocal:
+ return 0; /* TO DO */
case Qstatus:
qlock(b);
+ if(waserror()){
+ qunlock(b);
+ nexterror();
+ }
port = b->port[PORT(c->qid)];
if(port == 0)
strcpy(buf, "unbound\n");
@@ -318,16 +325,15 @@
}
ingood = port->in - port->inmulti - port->inunknown;
outgood = port->out - port->outmulti - port->outunknown;
- i += snprint(buf+i, sizeof(buf)-i,
+ snprint(buf+i, sizeof(buf)-i,
"in=%d(%d:%d:%d) out=%d(%d:%d:%d:%d)\n",
port->in, ingood, port->inmulti, port->inunknown,
port->out, outgood, port->outmulti,
port->outunknown, port->outfrag);
- USED(i);
}
- n = readstr(off, a, n, buf);
+ poperror();
qunlock(b);
- return n;
+ return readstr(off, a, n, buf);
case Qbctl:
snprint(buf, sizeof(buf), "%s tcpmss\ndelay %ld %ld\n",
b->tcpmss ? "set" : "clear", b->delay0, b->delayn);
@@ -513,7 +519,7 @@
Chan *ctl;
int type = 0, i, n;
ulong ownhash;
- char *dev, *dev2 = nil, *p;
+ char *dev, *dev2 = nil;
char buf[100], name[KNAMELEN], path[8*KNAMELEN];
static char usage[] = "usage: bind ether|tunnel name ownhash dev [dev2]";
@@ -524,7 +530,7 @@
if(argc != 4)
error(usage);
type = Tether;
- strncpy(name, argv[1], KNAMELEN-1);
+ strncpy(name, argv[1], KNAMELEN);
name[KNAMELEN-1] = 0;
// parseaddr(addr, argv[1], Eaddrlen);
} else if(strcmp(argv[0], "tunnel") == 0) {
@@ -531,13 +537,13 @@
if(argc != 5)
error(usage);
type = Ttun;
- strncpy(name, argv[1], KNAMELEN-1);
+ strncpy(name, argv[1], KNAMELEN);
name[KNAMELEN-1] = 0;
// parseip(addr, argv[1]);
dev2 = argv[4];
} else
error(usage);
- ownhash = strtoul(argv[2], 0, 0);
+ ownhash = atoi(argv[2]);
dev = argv[3];
for(i=0; i<b->nport; i++) {
port = b->port[i];
@@ -574,11 +580,9 @@
// check addr?
// get directory name
- n = devtab[ctl->type]->read(ctl, buf, sizeof(buf), 0);
+ n = devtab[ctl->type]->read(ctl, buf, sizeof(buf)-1, 0);
buf[n] = 0;
- for(p = buf; *p == ' '; p++)
- ;
- snprint(path, sizeof(path), "%s/%lud/data", dev, strtoul(p, 0, 0));
+ snprint(path, sizeof(path), "%s/%lud/data", dev, strtoul(buf, 0, 0));
// setup connection to be promiscuous
snprint(buf, sizeof(buf), "connect -1");
@@ -613,8 +617,9 @@
b->nport = port->id+1;
// assumes kproc always succeeds
- kproc("etherread", etherread, port); // poperror must be next
- port->ref++;
+ incref(port);
+ snprint(buf, sizeof(buf), "bridge:%s", dev);
+ kproc(buf, etherread, port);
}
// assumes b is locked
@@ -632,18 +637,18 @@
error(usage);
if(strcmp(argv[0], "ether") == 0) {
type = Tether;
- strncpy(name, argv[1], KNAMELEN-1);
+ strncpy(name, argv[1], KNAMELEN);
name[KNAMELEN-1] = 0;
// parseaddr(addr, argv[1], Eaddrlen);
} else if(strcmp(argv[0], "tunnel") == 0) {
type = Ttun;
- strncpy(name, argv[1], KNAMELEN-1);
+ strncpy(name, argv[1], KNAMELEN);
name[KNAMELEN-1] = 0;
// parseip(addr, argv[1]);
} else
error(usage);
if(argc == 3)
- ownhash = strtoul(argv[2], 0, 0);
+ ownhash = atoi(argv[2]);
else
ownhash = 0;
for(i=0; i<b->nport; i++) {
@@ -781,14 +786,21 @@
char c;
qlock(b);
+ if(waserror()) {
+ qunlock(b);
+ nexterror();
+ }
sec = TK2SEC(m->ticks);
n = 0;
for(i=0; i<CacheSize; i++)
if(b->cache[i].expire != 0)
n++;
+
n *= 51; // change if print format is changed
n += 10; // some slop at the end
- buf = smalloc(n);
+ buf = malloc(n);
+ if(buf == nil)
+ error(Enomem);
p = buf;
ep = buf + n;
ce = b->cache;
@@ -801,27 +813,22 @@
ce->port, ce->src, ce->dst, ce->expire+off, c);
}
*p = 0;
+ poperror();
qunlock(b);
+
return buf;
}
-// assumes b is locked
+// assumes b is locked, no error return
static void
ethermultiwrite(Bridge *b, Block *bp, Port *port)
{
Port *oport;
- Block *bp2;
Etherpkt *ep;
int i, mcast;
- if(waserror()) {
- if(bp)
- freeb(bp);
- nexterror();
- }
-
ep = (Etherpkt*)bp->rp;
mcast = ep->d[0] & 1; /* multicast bit of ethernet address */
@@ -841,26 +848,16 @@
// delay one so that the last write does not copy
if(oport != nil) {
b->copy++;
- bp2 = copyblock(bp, blocklen(bp));
- if(!waserror()) {
- etherwrite(oport, bp2);
- poperror();
- }
+ etherwrite(oport, copyblock(bp, blocklen(bp)));
}
oport = b->port[i];
}
// last write free block
- if(oport) {
- bp2 = bp; bp = nil; USED(bp);
- if(!waserror()) {
- etherwrite(oport, bp2);
- poperror();
- }
- } else
+ if(oport)
+ etherwrite(oport, bp);
+ else
freeb(bp);
-
- poperror();
}
static void
@@ -954,10 +951,10 @@
{
Port *port = a;
Bridge *b = port->bridge;
- Block *bp, *bp2;
+ Block *bp;
Etherpkt *ep;
Centry *ce;
- long md;
+ long md, n;
qlock(b);
port->readp = up; /* hide identity under a rock for unbind */
@@ -970,64 +967,56 @@
qlock(b);
break;
}
- if(0)
- print("devbridge: etherread: reading\n");
- bp = devtab[port->data[0]->type]->bread(port->data[0],
- ETHERMAXTU, 0);
- if(0)
- print("devbridge: etherread: blocklen = %d\n",
- blocklen(bp));
+ bp = devtab[port->data[0]->type]->bread(port->data[0], MaxMTU, 0);
poperror();
qlock(b);
- if(bp == nil || port->closed)
+ if(bp == nil)
break;
+ n = blocklen(bp);
+ if(port->closed || n < ETHERMINTU){
+ freeb(bp);
+ continue;
+ }
if(waserror()) {
// print("etherread bridge error\n");
- if(bp)
- freeb(bp);
+ freeb(bp);
continue;
}
- if(blocklen(bp) < ETHERMINTU)
- error("short packet");
port->in++;
ep = (Etherpkt*)bp->rp;
cacheupdate(b, ep->s, port->id);
if(b->tcpmss)
- tcpmsshack(ep, BLEN(bp));
+ tcpmsshack(ep, n);
/*
* delay packets to simulate a slow link
*/
- if(b->delay0 || b->delayn){
- md = b->delay0 + b->delayn * BLEN(bp);
+ if(b->delay0 != 0 || b->delayn != 0){
+ md = b->delay0 + b->delayn * n;
if(md > 0)
microdelay(md);
}
+ poperror(); /* must now dispose of bp */
+
if(ep->d[0] & 1) {
log(b, Logmcast, "multicast: port=%d src=%E dst=%E type=%#.4ux\n",
port->id, ep->s, ep->d, ep->type[0]<<8|ep->type[1]);
port->inmulti++;
- bp2 = bp; bp = nil;
- ethermultiwrite(b, bp2, port);
+ ethermultiwrite(b, bp, port);
} else {
ce = cachelookup(b, ep->d);
if(ce == nil) {
b->miss++;
port->inunknown++;
- bp2 = bp; bp = nil;
- ethermultiwrite(b, bp2, port);
+ ethermultiwrite(b, bp, port);
}else if(ce->port != port->id){
b->hit++;
- bp2 = bp; bp = nil;
- etherwrite(b->port[ce->port], bp2);
- }
+ etherwrite(b->port[ce->port], bp);
+ }else
+ freeb(bp);
}
-
- poperror();
- if(bp)
- freeb(bp);
}
// print("etherread: trying to exit\n");
port->readp = nil;
@@ -1061,7 +1050,6 @@
return 1;
}
-
static void
etherwrite(Port *port, Block *bp)
{
@@ -1075,13 +1063,16 @@
epkt = (Etherpkt*)bp->rp;
n = blocklen(bp);
if(port->type != Ttun || !fragment(epkt, n)) {
- devtab[port->data[1]->type]->bwrite(port->data[1], bp, 0);
+ if(!waserror()){
+ devtab[port->data[1]->type]->bwrite(port->data[1], bp, 0);
+ poperror();
+ }
return;
}
port->outfrag++;
if(waserror()){
freeblist(bp);
- nexterror();
+ return;
}
seglen = (TunnelMtu - ETHERHDRSIZE - IPHDR) & ~7;
@@ -1152,10 +1143,7 @@
static void
portfree(Port *port)
{
- port->ref--;
- if(port->ref < 0)
- panic("portfree: bad ref");
- if(port->ref > 0)
+ if(decref(port) != 0)
return;
if(port->data[0])