#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h" #include "ip.h" enum { X = 0, /* dimension */ Y = 1, Z = 2, N = 3, Chunk = 32, /* granularity of FIFO */ Pchunk = 8, /* Chunks in a packet */}; typedef struct Th Th;struct Th { u8int _0_[1]; /* Tpkt: 8 bytes */ u8int hint; /* ignored by IP for now */ u8int _1_[1]; u8int dst[N]; /* Destination Coordinates */ u8int _6_[2]; u8int _8_[8]; /* Tpkt: padding */ u8int _16_[16]; /* Ipv4 header: 20 bytes */ u8int ipv4dst[4];}; typedef struct Rock Rock;struct Rock { Fs* fs; /* file system we belong to */ Proc* read4p; /* v4 read process */ Chan* mchan4; /* v4 data channel */ u8int size[N];}; /* * Called by ipoput with a single block to write. */static voidtorusbwrite(Ipifc* ifc, Block* b, int, uchar*){ Th *th; Rock *r; int i, n; r = ifc->arg; b = padblock(b, ifc->medium->hsize); if(b->next) b = concatblock(b); n = ROUNDUP(BLEN(b), Chunk); if(BLEN(b) < n) b = adjustblock(b, n); /* * The naïve mapping of IP address to torus address is * to assign a Class A network to the torus and set the * 3 octets of the host number to x.y.z, with z being * the least significant. However, there will be a root * compute node with an all zero torus address and that * is reserved for use as a network number. Therefore * the mapping is modified by adding 1 to the torus z * coordinate to create the least significant octet of * the IP address. * Silently toss packets with a host address out of range. * The torus will generate an unrecoverable error if it * sees an address outwith its dimensions. * Should there be a some ICMP notification thingy here * (address unreachable)? */ th = (Th*)b->rp; th->hint = 0; th->dst[X] = th->ipv4dst[1]; th->dst[Y] = th->ipv4dst[2]; th->dst[Z] = th->ipv4dst[3]-1; if(th->dst[Z] >= 254){ /* IP was 255 or 0 */ freeb(b); return; } for(i = 0; i < N; i++){ if(th->dst[i] >= r->size[i]){ freeb(b); return; } } r->mchan4->dev->bwrite(r->mchan4, b, 0); ifc->out++;} /* * Process to read from the device. */static voidtorusread4(void* a){ Rock *r; Block *b; Ipifc *ifc; ifc = a; r = ifc->arg; r->read4p = up; if(waserror()){ r->read4p = nil; pexit("hangup", 1); } for(;;){ b = r->mchan4->dev->bread(r->mchan4, ifc->maxtu, 0); if(!canrlock(ifc)){ freeb(b); continue; } if(waserror()){ runlock(ifc); nexterror(); } ifc->in++; b->rp += ifc->medium->hsize; if(ifc->lifc == nil) freeb(b); else ipiput4(r->fs, ifc, b); runlock(ifc); poperror(); }} /* * Called with ifc wlock'd. */static voidtorusunbind(Ipifc* ifc){ Rock *r; r = ifc->arg; if(r->read4p != nil) postnote(r->read4p, 1, "unbind", NUser); /* wait for readers to die */ while(r->read4p != nil) tsleep(&up->sleep, return0, 0, 300); if(r->mchan4 != nil) cclose(r->mchan4); free(r);} static inttorusparse(u8int d[3], char* item, char* buf){ int n; char *p; if((p = strstr(buf, item)) == nil || (p != buf && *(p-1) != '\n')) return -1; n = strlen(item); if(strlen(p) < n+sizeof(": x 0 y 0 z 0")) return -1; p += n+sizeof(": x ")-1; if(strncmp(p-4, ": x ", 4) != 0) return -1; if((n = strtol(p, &p, 0)) > 255 || *p != ' ' || *(p+1) != 'y') return -1; d[0] = n; if((n = strtol(p+2, &p, 0)) > 255 || *p != ' ' || *(p+1) != 'z') return -1; d[1] = n; if((n = strtol(p+2, &p, 0)) > 255 || (*p != '\n' && *p != '\0')) return -1; d[2] = n; return 0;} /* * Called to bind an Ipifc to a torus device. * Ifc is qlock'd. */static voidtorusbind(Ipifc* ifc, int argc, char* argv[]){ int n; Rock *r; Chan *mchan4, *schan; char *buf, stats[Maxpath]; if(argc < 2) error(Ebadarg); mchan4 = nil; buf = nil; if(waserror()){ if(mchan4 != nil) cclose(mchan4); if(buf != nil) free(buf); nexterror(); } mchan4 = namec(argv[2], Aopen, ORDWR, 0); /* * Get the dimensions of the torus/mesh from the device * 'stats' file so attempts to send outside can be detected * in torusbwrite. */ snprint(stats, sizeof(stats), "%sstatus", argv[2]); buf = smalloc(2*READSTR); schan = namec(stats, Aopen, OREAD, 0); if(waserror()){ cclose(schan); nexterror(); } n = schan->dev->read(schan, buf, 511, 0); cclose(schan); poperror(); buf[n] = 0; r = smalloc(sizeof(*r)); if(torusparse(r->size, "size", buf) < 0){ free(buf); error(Eio); } r->mchan4 = mchan4; r->fs = ifc->conv->p->f; ifc->arg = r; ifc->mbps = 1001; free(buf); poperror(); kproc("torusread4", torusread4, ifc);} static Medium torusmedium = { .name = "torus", .hsize = 16, .mintu = Chunk, .maxtu = Chunk*Pchunk, .maclen = N, .bind = torusbind, .unbind = torusunbind, .bwrite = torusbwrite,}; voidtorusmediumlink(void){ addipmedium(&torusmedium);}
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#include "ip.h"
enum {
X = 0, /* dimension */
Y = 1,
Z = 2,
N = 3,
Chunk = 32, /* granularity of FIFO */
Pchunk = 8, /* Chunks in a packet */
};
typedef struct Th Th;
struct Th {
u8int _0_[1]; /* Tpkt: 8 bytes */
u8int hint; /* ignored by IP for now */
u8int _1_[1];
u8int dst[N]; /* Destination Coordinates */
u8int _6_[2];
u8int _8_[8]; /* Tpkt: padding */
u8int _16_[16]; /* Ipv4 header: 20 bytes */
u8int ipv4dst[4];
};
typedef struct Rock Rock;
struct Rock {
Fs* fs; /* file system we belong to */
Proc* read4p; /* v4 read process */
Chan* mchan4; /* v4 data channel */
u8int size[N];
};
/*
* Called by ipoput with a single block to write.
*/
static void
torusbwrite(Ipifc* ifc, Block* b, int, uchar*)
{
Th *th;
Rock *r;
int i, n;
r = ifc->arg;
b = padblock(b, ifc->medium->hsize);
if(b->next)
b = concatblock(b);
n = ROUNDUP(BLEN(b), Chunk);
if(BLEN(b) < n)
b = adjustblock(b, n);
/*
* The naïve mapping of IP address to torus address is
* to assign a Class A network to the torus and set the
* 3 octets of the host number to x.y.z, with z being
* the least significant. However, there will be a root
* compute node with an all zero torus address and that
* is reserved for use as a network number. Therefore
* the mapping is modified by adding 1 to the torus z
* coordinate to create the least significant octet of
* the IP address.
* Silently toss packets with a host address out of range.
* The torus will generate an unrecoverable error if it
* sees an address outwith its dimensions.
* Should there be a some ICMP notification thingy here
* (address unreachable)?
*/
th = (Th*)b->rp;
th->hint = 0;
th->dst[X] = th->ipv4dst[1];
th->dst[Y] = th->ipv4dst[2];
th->dst[Z] = th->ipv4dst[3]-1;
if(th->dst[Z] >= 254){ /* IP was 255 or 0 */
freeb(b);
return;
}
for(i = 0; i < N; i++){
if(th->dst[i] >= r->size[i]){
freeb(b);
return;
}
}
r->mchan4->dev->bwrite(r->mchan4, b, 0);
ifc->out++;
}
/*
* Process to read from the device.
*/
static void
torusread4(void* a)
{
Rock *r;
Block *b;
Ipifc *ifc;
ifc = a;
r = ifc->arg;
r->read4p = up;
if(waserror()){
r->read4p = nil;
pexit("hangup", 1);
}
for(;;){
b = r->mchan4->dev->bread(r->mchan4, ifc->maxtu, 0);
if(!canrlock(ifc)){
freeb(b);
continue;
}
if(waserror()){
runlock(ifc);
nexterror();
}
ifc->in++;
b->rp += ifc->medium->hsize;
if(ifc->lifc == nil)
freeb(b);
else
ipiput4(r->fs, ifc, b);
runlock(ifc);
poperror();
}
}
/*
* Called with ifc wlock'd.
*/
static void
torusunbind(Ipifc* ifc)
{
Rock *r;
r = ifc->arg;
if(r->read4p != nil)
postnote(r->read4p, 1, "unbind", NUser);
/* wait for readers to die */
while(r->read4p != nil)
tsleep(&up->sleep, return0, 0, 300);
if(r->mchan4 != nil)
cclose(r->mchan4);
free(r);
}
static int
torusparse(u8int d[3], char* item, char* buf)
{
int n;
char *p;
if((p = strstr(buf, item)) == nil || (p != buf && *(p-1) != '\n'))
return -1;
n = strlen(item);
if(strlen(p) < n+sizeof(": x 0 y 0 z 0"))
return -1;
p += n+sizeof(": x ")-1;
if(strncmp(p-4, ": x ", 4) != 0)
return -1;
if((n = strtol(p, &p, 0)) > 255 || *p != ' ' || *(p+1) != 'y')
return -1;
d[0] = n;
if((n = strtol(p+2, &p, 0)) > 255 || *p != ' ' || *(p+1) != 'z')
return -1;
d[1] = n;
if((n = strtol(p+2, &p, 0)) > 255 || (*p != '\n' && *p != '\0'))
return -1;
d[2] = n;
return 0;
}
/*
* Called to bind an Ipifc to a torus device.
* Ifc is qlock'd.
*/
static void
torusbind(Ipifc* ifc, int argc, char* argv[])
{
int n;
Rock *r;
Chan *mchan4, *schan;
char *buf, stats[Maxpath];
if(argc < 2)
error(Ebadarg);
mchan4 = nil;
buf = nil;
if(waserror()){
if(mchan4 != nil)
cclose(mchan4);
if(buf != nil)
free(buf);
nexterror();
}
mchan4 = namec(argv[2], Aopen, ORDWR, 0);
/*
* Get the dimensions of the torus/mesh from the device
* 'stats' file so attempts to send outside can be detected
* in torusbwrite.
*/
snprint(stats, sizeof(stats), "%sstatus", argv[2]);
buf = smalloc(2*READSTR);
schan = namec(stats, Aopen, OREAD, 0);
if(waserror()){
cclose(schan);
nexterror();
}
n = schan->dev->read(schan, buf, 511, 0);
cclose(schan);
poperror();
buf[n] = 0;
r = smalloc(sizeof(*r));
if(torusparse(r->size, "size", buf) < 0){
free(buf);
error(Eio);
}
r->mchan4 = mchan4;
r->fs = ifc->conv->p->f;
ifc->arg = r;
ifc->mbps = 1001;
free(buf);
poperror();
kproc("torusread4", torusread4, ifc);
}
static Medium torusmedium = {
.name = "torus",
.hsize = 16,
.mintu = Chunk,
.maxtu = Chunk*Pchunk,
.maclen = N,
.bind = torusbind,
.unbind = torusunbind,
.bwrite = torusbwrite,
};
void
torusmediumlink(void)
{
addipmedium(&torusmedium);
}