add erik quanstros vblade utility
parent
e93cd703a2
commit
6379939642
|
@ -271,7 +271,7 @@ Unused.
|
|||
.\" .IR vblade (1),
|
||||
.IR sd (3),
|
||||
.IR sdaoe (3),
|
||||
.IR aoesrv (8),
|
||||
.IR vblade (8),
|
||||
.IR snoopy (8)
|
||||
.br
|
||||
.BR http://www.coraid.com/documents/AoEr10.txt
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
.TH VBLADE 8
|
||||
.SH NAME
|
||||
vblade \- virtual AoE target
|
||||
.SH SYNOPSIS
|
||||
.B disk/vblade
|
||||
[
|
||||
.B -ir
|
||||
] [
|
||||
.B -s
|
||||
.I size
|
||||
] [
|
||||
.B -a
|
||||
.I shelf.slot
|
||||
] [
|
||||
.B -c
|
||||
.I config
|
||||
]
|
||||
.B file
|
||||
[
|
||||
.B -e
|
||||
ether
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
For each
|
||||
.I file
|
||||
specified,
|
||||
.I vblade
|
||||
serves it as an AoE (ATA-over-Ethernet) target via
|
||||
the specified interfaces. The default interface is
|
||||
.BR /net/ether0 .
|
||||
Since AoE uses raw Ethernet frames, the target is
|
||||
only visible on the local ethernet segment.
|
||||
.PP
|
||||
All target-related options are reset for each
|
||||
.IR file .
|
||||
.SS Options
|
||||
.TP \w'\fL-e\ \fIetherXX'u
|
||||
.B -i
|
||||
Initialize the configuration header in
|
||||
.IR file .
|
||||
All previous configuration information is lost. Without this option,
|
||||
configuration is read from
|
||||
.I file
|
||||
and command like options override previous settings.
|
||||
.TP
|
||||
.B -r
|
||||
Raw. Do not use a configuration header. This is useful when
|
||||
exporting a device or file not generally exported by
|
||||
.IR vblade .
|
||||
.TP
|
||||
.BI -s " n"
|
||||
The exported target will have size
|
||||
.IR n ,
|
||||
rather than the available space in the target. A size may end in
|
||||
.LR p ,
|
||||
.LR t ,
|
||||
.LR g ,
|
||||
.LR m ,
|
||||
or
|
||||
.LR k
|
||||
to specify a customary
|
||||
.I binary
|
||||
multiplier.
|
||||
.TP
|
||||
.BI -a " m.n"
|
||||
Specify the shelf and slot (or major and minor) address of the target.
|
||||
Valid shelf numbers are between 0 and 65534. Valid slots are 0-255.
|
||||
.TP
|
||||
.BI -c " s"
|
||||
Set the AoE config string to
|
||||
.IR s .
|
||||
.TP
|
||||
.BI -e " ether"
|
||||
Listen to the network port
|
||||
.IR ether.
|
||||
Multiple ports may be specified.
|
||||
.SH SEE ALSO
|
||||
.IR aoe (3),
|
||||
.IR sdaoe (3),
|
||||
.IR http://www.coraid.com/documents/AoEr11.txt .
|
||||
.SH SOURCE
|
||||
.B /sys/src/cmd/disk/vblade
|
||||
.SH BUGS
|
||||
Security depends on control of the local Ethernet segment. It may be
|
||||
unwise to serve AoE on a segment bridged to a wireless network.
|
|
@ -14,6 +14,7 @@ DIRS=\
|
|||
prep\
|
||||
smart\
|
||||
# sacfs\
|
||||
vblade\
|
||||
|
||||
OFILES=
|
||||
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
enum{
|
||||
ACata,
|
||||
ACconfig,
|
||||
};
|
||||
|
||||
enum{
|
||||
AQCread,
|
||||
AQCtest,
|
||||
AQCprefix,
|
||||
AQCset,
|
||||
AQCfset,
|
||||
};
|
||||
|
||||
enum{
|
||||
AEcmd = 1,
|
||||
AEarg,
|
||||
AEdev,
|
||||
AEcfg,
|
||||
AEver,
|
||||
};
|
||||
|
||||
enum{
|
||||
Aoetype = 0x88a2,
|
||||
Aoesectsz = 512,
|
||||
Aoemaxcfg = 1024,
|
||||
|
||||
Aoehsz = 24,
|
||||
Aoeatasz = 12,
|
||||
Aoecfgsz = 8,
|
||||
Aoerrsz = 2,
|
||||
Aoemsz = 4,
|
||||
Aoemdsz = 8,
|
||||
|
||||
Aoever = 1,
|
||||
|
||||
AFerr = 1<<2,
|
||||
AFrsp = 1<<3,
|
||||
|
||||
AAFwrite = 1,
|
||||
AAFext = 1<<6,
|
||||
};
|
||||
|
||||
#pragma pack on
|
||||
|
||||
typedef struct{
|
||||
uchar dst[Eaddrlen];
|
||||
uchar src[Eaddrlen];
|
||||
uchar type[2];
|
||||
uchar verflag;
|
||||
uchar error;
|
||||
uchar major[2];
|
||||
uchar minor;
|
||||
uchar cmd;
|
||||
uchar tag[4];
|
||||
}Aoehdr;
|
||||
|
||||
typedef struct{
|
||||
Aoehdr;
|
||||
uchar aflag;
|
||||
uchar errfeat;
|
||||
uchar scnt;
|
||||
uchar cmdstat;
|
||||
uchar lba[6];
|
||||
uchar res[2];
|
||||
}Aoeata;
|
||||
|
||||
typedef struct{
|
||||
Aoehdr;
|
||||
uchar bufcnt[2];
|
||||
uchar fwver[2];
|
||||
uchar scnt;
|
||||
uchar verccmd;
|
||||
uchar cslen[2];
|
||||
}Aoeqc;
|
|
@ -0,0 +1,12 @@
|
|||
</$objtype/mkfile
|
||||
|
||||
TARG=vblade
|
||||
|
||||
OFILES=\
|
||||
vblade.$O\
|
||||
|
||||
HFILES=aoe.h
|
||||
|
||||
BIN=/$objtype/bin/disk
|
||||
|
||||
</sys/src/cmd/mkone
|
|
@ -0,0 +1,663 @@
|
|||
/*
|
||||
* vblade -- virtual aoe target
|
||||
* copyright © 2007 erik quanstrom
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include <ip.h> /* irony */
|
||||
#include <fis.h>
|
||||
|
||||
enum {
|
||||
Eaddrlen = 6, /* only defined in kernel */
|
||||
};
|
||||
#include "aoe.h"
|
||||
|
||||
enum {
|
||||
Fclone,
|
||||
Fdata,
|
||||
Flast,
|
||||
|
||||
Fraw = 1<<0,
|
||||
|
||||
Nether = 8,
|
||||
Nvblade = 8,
|
||||
Maxpkt = 10000,
|
||||
Hdrlba = 128,
|
||||
Conflen = 1024,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int iflag;
|
||||
int flag;
|
||||
int shelf;
|
||||
int slot;
|
||||
uvlong maxlba;
|
||||
char *config;
|
||||
} Conf;
|
||||
|
||||
typedef struct {
|
||||
char magic[32];
|
||||
char size[32];
|
||||
char address[16];
|
||||
char configlen[6];
|
||||
char pad[512-32-32-16-6];
|
||||
char config[Conflen];
|
||||
} Vbhdr;
|
||||
|
||||
typedef struct {
|
||||
Vbhdr hdr;
|
||||
vlong maxlba;
|
||||
vlong hdrsz;
|
||||
int shelf;
|
||||
int slot;
|
||||
int clen;
|
||||
int flag;
|
||||
int fd;
|
||||
} Vblade;
|
||||
|
||||
static Vblade vblade[Nvblade];
|
||||
static int nblade;
|
||||
|
||||
static char *ethertab[Nether] = {
|
||||
"/net/ether0",
|
||||
};
|
||||
static int etheridx = 1;
|
||||
static int efdtab[Nether*Flast];
|
||||
static char pkttab[Nether][Maxpkt];
|
||||
static char bctab[Nether][Maxpkt];
|
||||
static int mtutab[Nether];
|
||||
static char Magic[] = "aoe vblade\n";
|
||||
|
||||
static int
|
||||
getmtu(char *p)
|
||||
{
|
||||
char buf[50];
|
||||
int fd, mtu;
|
||||
|
||||
snprint(buf, sizeof buf, "%s/mtu", p);
|
||||
if((fd = open(buf, OREAD)) == -1)
|
||||
return 2;
|
||||
if(read(fd, buf, 36) < 0)
|
||||
return 2;
|
||||
close(fd);
|
||||
buf[36] = 0;
|
||||
mtu = strtoul(buf+12, 0, 0)-sizeof(Aoehdr);
|
||||
return mtu>>9;
|
||||
}
|
||||
|
||||
int
|
||||
parseshelf(char *s, int *shelf, int *slot)
|
||||
{
|
||||
int a, b;
|
||||
|
||||
a = strtoul(s, &s, 0);
|
||||
if(*s++ != '.')
|
||||
return -1;
|
||||
b = strtoul(s, &s, 0);
|
||||
if(*s != 0)
|
||||
return -1;
|
||||
*shelf = a;
|
||||
*slot = b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static vlong
|
||||
getsize(char *s)
|
||||
{
|
||||
static char tab[] = "ptgmk";
|
||||
char *p;
|
||||
vlong v;
|
||||
|
||||
v = strtoull(s, &s, 0);
|
||||
while((p = strchr(tab, *s++)) && *p)
|
||||
while(*p++)
|
||||
v *= 1024;
|
||||
if(s[-1])
|
||||
return -1;
|
||||
return v;
|
||||
}
|
||||
|
||||
vlong
|
||||
sizetolba(vlong size)
|
||||
{
|
||||
if(size < 512 || size & 0x1ff){
|
||||
fprint(2, "invalid size %lld\n", size);
|
||||
exits("size");
|
||||
}
|
||||
return size>>9;
|
||||
}
|
||||
|
||||
static int
|
||||
savevblade(int fd, Vblade *vb)
|
||||
{
|
||||
int n, r;
|
||||
char *p;
|
||||
|
||||
sprint(vb->hdr.size, "%lld", vb->maxlba<<9);
|
||||
sprint(vb->hdr.address, "%d.%d", vb->shelf, vb->slot);
|
||||
sprint(vb->hdr.configlen, "%d", vb->clen);
|
||||
|
||||
if(vb->flag & Fraw)
|
||||
return 0;
|
||||
p = (char*)vb;
|
||||
for(n = 0; n < sizeof *vb; n += r)
|
||||
if((r = pwrite(fd, p+n, sizeof *vb-n, n)) <= 0)
|
||||
break;
|
||||
if(n != sizeof *vb)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char*
|
||||
chkvblade(int fd, Vblade *vb)
|
||||
{
|
||||
Vbhdr *h;
|
||||
|
||||
h = &vb->hdr;
|
||||
if(readn(fd, (char*)h, sizeof *h) != sizeof *h)
|
||||
return "bad read";
|
||||
if(memcmp(h->magic, Magic, sizeof Magic))
|
||||
return "bad magic";
|
||||
h->size[sizeof h->size-1] = 0;
|
||||
vb->maxlba = sizetolba(strtoull(h->size, 0, 0));
|
||||
if(parseshelf(h->address, &vb->shelf, &vb->slot) == -1)
|
||||
return "bad shelf";
|
||||
h->configlen[sizeof h->configlen-1] = 0;
|
||||
vb->clen = strtoul(h->configlen, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
checkfile(char *s, Vblade *vb, int iflag)
|
||||
{
|
||||
char *e;
|
||||
|
||||
vb->fd = open(s, ORDWR);
|
||||
if(vb->fd == -1)
|
||||
sysfatal("can't open backing store: %r");
|
||||
if(iflag == 0 && (e = chkvblade(vb->fd, vb)))
|
||||
sysfatal("invalid vblade %s", e);
|
||||
}
|
||||
|
||||
void
|
||||
recheck(int fd, Vblade *vb)
|
||||
{
|
||||
Dir *d;
|
||||
vlong v;
|
||||
|
||||
d = dirfstat(fd);
|
||||
if(d == 0)
|
||||
sysfatal("can't stat: %r");
|
||||
if((vb->flag & Fraw) == 0)
|
||||
vb->hdrsz = Hdrlba;
|
||||
v = sizetolba(d->length & ~0x1ff) - vb->hdrsz;
|
||||
free(d);
|
||||
if(vb->maxlba > v)
|
||||
sysfatal("cmdline size too large (%lld sector overhead)", vb->hdrsz);
|
||||
if(vb->maxlba == 0)
|
||||
vb->maxlba = v;
|
||||
|
||||
savevblade(fd, vb);
|
||||
}
|
||||
|
||||
int
|
||||
aoeopen(char *e, int fds[])
|
||||
{
|
||||
char buf[128], ctl[13];
|
||||
int n;
|
||||
|
||||
snprint(buf, sizeof buf, "%s/clone", e);
|
||||
if((fds[Fclone] = open(buf, ORDWR)) == -1)
|
||||
return -1;
|
||||
memset(ctl, 0, sizeof ctl);
|
||||
if(read(fds[Fclone], ctl, sizeof ctl - 1) < 0)
|
||||
return -1;
|
||||
n = atoi(ctl);
|
||||
snprint(buf, sizeof buf, "connect %d", Aoetype);
|
||||
if(write(fds[Fclone], buf, strlen(buf)) != strlen(buf))
|
||||
return -1;
|
||||
snprint(buf, sizeof buf, "%s/%d/data", e, n);
|
||||
fds[Fdata] = open(buf, ORDWR);
|
||||
return fds[Fdata];
|
||||
}
|
||||
|
||||
void
|
||||
replyhdr(Aoehdr *h, Vblade *vblade)
|
||||
{
|
||||
uchar ea[Eaddrlen];
|
||||
|
||||
memmove(ea, h->dst, Eaddrlen);
|
||||
memmove(h->dst, h->src, Eaddrlen);
|
||||
memmove(h->src, ea, Eaddrlen);
|
||||
|
||||
hnputs(h->major, vblade->shelf);
|
||||
h->minor = vblade->slot;
|
||||
h->verflag |= AFrsp;
|
||||
}
|
||||
|
||||
static int
|
||||
serveconfig(Aoeqc *q, Vblade *vb, int mtu)
|
||||
{
|
||||
int cmd, reqlen, len;
|
||||
char *cfg;
|
||||
|
||||
if(memcmp(q->src, q->dst, Eaddrlen) == 0)
|
||||
return -1;
|
||||
|
||||
reqlen = nhgets(q->cslen);
|
||||
len = vb->clen;
|
||||
cmd = q->verccmd&0xf;
|
||||
cfg = (char*)(q+1);
|
||||
|
||||
switch(cmd){
|
||||
case AQCtest:
|
||||
if(reqlen != len)
|
||||
return -1;
|
||||
case AQCprefix:
|
||||
if(reqlen > len)
|
||||
return -1;
|
||||
if(memcmp(vb->hdr.config, cfg, reqlen) != 0)
|
||||
return -1;
|
||||
case AQCread:
|
||||
break;
|
||||
case AQCset:
|
||||
if(len && len != reqlen || memcmp(vb->hdr.config, cfg, reqlen) != 0){
|
||||
q->verflag |= AFerr;
|
||||
q->error = AEcfg;
|
||||
break;
|
||||
}
|
||||
case AQCfset:
|
||||
if(reqlen > Conflen){
|
||||
q->verflag |= AFerr;
|
||||
q->error = AEarg;
|
||||
break;
|
||||
}
|
||||
memset(vb->hdr.config, 0, sizeof vb->hdr.config);
|
||||
memmove(vb->hdr.config, cfg, reqlen);
|
||||
vb->clen = len = reqlen;
|
||||
savevblade(vb->fd, vb);
|
||||
break;
|
||||
default:
|
||||
q->verflag |= AFerr;
|
||||
q->error = AEarg;
|
||||
}
|
||||
|
||||
memmove(cfg, vb->hdr.config, len);
|
||||
hnputs(q->cslen, len);
|
||||
hnputs(q->bufcnt, 24);
|
||||
q->scnt = mtu;
|
||||
hnputs(q->fwver, 2323);
|
||||
q->verccmd = Aoever<<4 | cmd;
|
||||
|
||||
return len+sizeof *q;
|
||||
}
|
||||
|
||||
static ushort ident[256] = {
|
||||
[47] 0x8000,
|
||||
[49] 0x0200,
|
||||
[50] 0x4000,
|
||||
[83] 0x5400,
|
||||
[84] 0x4000,
|
||||
[86] 0x1400,
|
||||
[87] 0x4000,
|
||||
[93] 0x400b,
|
||||
};
|
||||
|
||||
static void
|
||||
idmoveto(char *a, int idx, int len, char *s)
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = a+idx*2;
|
||||
for(; len > 0; len -= 2) {
|
||||
if(*s == 0)
|
||||
p[1] = ' ';
|
||||
else
|
||||
p[1] = *s++;
|
||||
if (*s == 0)
|
||||
p[0] = ' ';
|
||||
else
|
||||
p[0] = *s++;
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
lbamoveto(char *p, int idx, int n, vlong lba)
|
||||
{
|
||||
int i;
|
||||
|
||||
p += idx*2;
|
||||
for(i = 0; i < n; i++)
|
||||
*p++ = lba>>i*8;
|
||||
}
|
||||
|
||||
enum {
|
||||
Crd = 0x20,
|
||||
Crdext = 0x24,
|
||||
Cwr = 0x30,
|
||||
Cwrext = 0x34,
|
||||
Cid = 0xec,
|
||||
};
|
||||
|
||||
static uvlong
|
||||
getlba(uchar *p)
|
||||
{
|
||||
uvlong v;
|
||||
|
||||
v = p[0];
|
||||
v |= p[1]<<8;
|
||||
v |= p[2]<<16;
|
||||
v |= p[3]<<24;
|
||||
v |= (uvlong)p[4]<<32;
|
||||
v |= (uvlong)p[5]<<40;
|
||||
return v;
|
||||
}
|
||||
|
||||
static void
|
||||
putlba(uchar *p, vlong lba)
|
||||
{
|
||||
p[0] = lba;
|
||||
p[1] = lba>>8;
|
||||
p[2] = lba>>16;
|
||||
p[3] = lba>>24;
|
||||
p[5] = lba>>32;
|
||||
p[6] = lba>>40;
|
||||
}
|
||||
|
||||
static int
|
||||
serveata(Aoeata *a, Vblade *vb, int mtu)
|
||||
{
|
||||
char *buf;
|
||||
int rbytes, bytes, len;
|
||||
vlong lba, off;
|
||||
|
||||
buf = (char*)(a+1);
|
||||
lba = getlba(a->lba);
|
||||
len = a->scnt<<9;
|
||||
off = lba+vb->hdrsz<<9;
|
||||
|
||||
if(a->scnt > mtu || a->scnt == 0){
|
||||
a->verflag |= AFerr;
|
||||
a->cmdstat = ASdrdy|ASerr;
|
||||
a->error = AEarg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(a->cmdstat != Cid)
|
||||
if(lba+a->scnt > vb->maxlba){
|
||||
a->errfeat = Eidnf;
|
||||
a->cmdstat = ASdrdy|ASerr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(a->cmdstat&0xf0 == 0x20)
|
||||
lba &= 0xfffffff;
|
||||
switch(a->cmdstat){
|
||||
default:
|
||||
a->errfeat = Eabrt;
|
||||
a->cmdstat = ASdrdy|ASerr;
|
||||
return 0;
|
||||
case Cid:
|
||||
memmove(buf, ident, sizeof ident);
|
||||
idmoveto(buf, 27, 40, "Plan 9 Vblade");
|
||||
idmoveto(buf, 10, 20, "serial#");
|
||||
idmoveto(buf, 23, 8, "2");
|
||||
lbamoveto(buf, 60, 4, vb->maxlba);
|
||||
lbamoveto(buf, 100, 8, vb->maxlba);
|
||||
a->cmdstat = ASdrdy;
|
||||
return 512;
|
||||
break;
|
||||
case Crd:
|
||||
case Crdext:
|
||||
bytes = pread(vb->fd, buf, len, off);
|
||||
rbytes = bytes;
|
||||
break;
|
||||
case Cwr:
|
||||
case Cwrext:
|
||||
bytes = pwrite(vb->fd, buf, len, off);
|
||||
rbytes = 0;
|
||||
break;
|
||||
}
|
||||
if(bytes != len){
|
||||
a->errfeat = Eabrt;
|
||||
a->cmdstat = ASdf|ASerr;
|
||||
putlba(a->lba, lba+(len-bytes)>>9);
|
||||
return 0;
|
||||
}
|
||||
|
||||
putlba(a->lba, lba+a->scnt);
|
||||
a->scnt = 0;
|
||||
a->errfeat = 0;
|
||||
a->cmdstat = ASdrdy;
|
||||
|
||||
return rbytes;
|
||||
}
|
||||
|
||||
static int
|
||||
myea(uchar ea[6], char *p)
|
||||
{
|
||||
char buf[50];
|
||||
int fd;
|
||||
|
||||
snprint(buf, sizeof buf, "%s/addr", p);
|
||||
if((fd = open(buf, OREAD)) == -1)
|
||||
return -1;
|
||||
if(read(fd, buf, 12) < 12)
|
||||
return -1;
|
||||
close(fd);
|
||||
return parseether(ea, buf);
|
||||
}
|
||||
|
||||
static int
|
||||
bcastpkt(Aoeqc *h, uint shelf, uint slot, int i)
|
||||
{
|
||||
myea(h->dst, ethertab[i]);
|
||||
memset(h->src, 0xff, Eaddrlen);
|
||||
hnputs(h->type, Aoetype);
|
||||
hnputs(h->major, shelf);
|
||||
h->minor = slot;
|
||||
h->cmd = ACconfig;
|
||||
*(u32int*)h->tag = 0;
|
||||
return Aoehsz + Aoecfgsz;
|
||||
}
|
||||
|
||||
int
|
||||
bladereply(Vblade *v, int i, int fd, char *pkt)
|
||||
{
|
||||
int n;
|
||||
Aoehdr *h;
|
||||
|
||||
h = (Aoehdr*)pkt;
|
||||
switch(h->cmd){
|
||||
case ACata:
|
||||
n = serveata((Aoeata*)h, v, mtutab[i]);
|
||||
n += sizeof(Aoeata);
|
||||
break;
|
||||
case ACconfig:
|
||||
n = serveconfig((Aoeqc*)h, v, mtutab[i]);
|
||||
break;
|
||||
default:
|
||||
n = -1;
|
||||
break;
|
||||
}
|
||||
if(n == -1)
|
||||
return -1;
|
||||
replyhdr(h, v);
|
||||
if(n < 60){
|
||||
memset(pkt+n, 0, 60-n);
|
||||
n = 60;
|
||||
}
|
||||
if(write(fd, h, n) != n){
|
||||
fprint(2, "write to %s failed: %r\n", ethertab[i]);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
serve(void *v)
|
||||
{
|
||||
int i, j, popcnt, vec, n, s, efd;
|
||||
char *pkt, *bcpkt;
|
||||
Aoehdr *h;
|
||||
|
||||
fmtinstall('E', eipfmt);
|
||||
i = (int)(uintptr)v;
|
||||
|
||||
efd = efdtab[i*Flast+Fdata];
|
||||
pkt = pkttab[i];
|
||||
bcpkt = bctab[i];
|
||||
|
||||
n = 60;
|
||||
h = (Aoehdr*)pkt;
|
||||
bcastpkt((Aoeqc*)pkt, 0xffff, 0xff, i);
|
||||
goto start;
|
||||
|
||||
for(;;){
|
||||
n = read(efd, pkt, Maxpkt);
|
||||
start:
|
||||
if(n < 60 || h->verflag & AFrsp)
|
||||
continue;
|
||||
s = nhgets(h->major);
|
||||
popcnt = 0;
|
||||
vec = 0;
|
||||
for(j = 0; j < nblade; j++){
|
||||
if((vblade[j].shelf == s || s == 0xffff)
|
||||
&& (vblade[j].slot == h->minor || h->minor == 0xff)){
|
||||
popcnt++;
|
||||
vec |= 1<<j;
|
||||
}
|
||||
}
|
||||
for(j = 0; popcnt>0 && j < nblade; j++){
|
||||
if((vec & 1<<j) == 0)
|
||||
continue;
|
||||
if(popcnt>0){
|
||||
memcpy(bcpkt, pkt, n);
|
||||
bladereply(vblade + j, i, efd, bcpkt);
|
||||
}else
|
||||
bladereply(vblade + j, i, efd, pkt);
|
||||
popcnt--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
launch(char *tab[], int fdtab[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; tab[i]; i++){
|
||||
if(aoeopen(tab[i], fdtab+Flast*i) < 0)
|
||||
sysfatal("network open: %r");
|
||||
/*
|
||||
* use proc not threads. otherwise we will block on read/write.
|
||||
*/
|
||||
proccreate(serve, (void*)i, 32*1024);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "vblade [-ir] [-s size] [-a shelf.slot] [-c config] [-e ether] file\n");
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
goblade(Vblade *vblade, char *file, Conf *c)
|
||||
{
|
||||
char *anal;
|
||||
|
||||
if(c->iflag == 1)
|
||||
memcpy(vblade->hdr.magic, Magic, sizeof Magic);
|
||||
checkfile(file, vblade, c->iflag);
|
||||
|
||||
vblade->flag = c->flag;
|
||||
if(c->shelf != -1){
|
||||
vblade->shelf = c->shelf;
|
||||
vblade->slot = c->slot;
|
||||
}
|
||||
if(c->maxlba > 0)
|
||||
vblade->maxlba = c->maxlba;
|
||||
if(c->config != nil)
|
||||
memmove(vblade->hdr.config, c->config, vblade->clen = strlen(c->config));
|
||||
|
||||
recheck(vblade->fd, vblade);
|
||||
|
||||
anal = "";
|
||||
if(vblade->maxlba > 1)
|
||||
anal = "s";
|
||||
fprint(2, "lblade %d.%d %lld sector%s\n", vblade->shelf, vblade->slot, vblade->maxlba, anal);
|
||||
}
|
||||
|
||||
void
|
||||
threadmain(int argc, char **argv)
|
||||
{
|
||||
int i, lastc, anye;
|
||||
Conf c;
|
||||
|
||||
anye = 0;
|
||||
for(;;){
|
||||
if(nblade == nelem(vblade))
|
||||
sysfatal("too many blades");
|
||||
c = (Conf){0, 0, -1, -1, 0, nil};
|
||||
lastc = 0;
|
||||
ARGBEGIN{
|
||||
case 'a':
|
||||
lastc = 'a';
|
||||
if(parseshelf(EARGF(usage()), &c.shelf, &c.slot) == -1)
|
||||
sysfatal("bad vblade address");
|
||||
break;
|
||||
case 'c':
|
||||
lastc = 'c';
|
||||
c.config = EARGF(usage());
|
||||
break;
|
||||
case 'e':
|
||||
lastc = 'e';
|
||||
if(anye++ == 0)
|
||||
etheridx = 0;
|
||||
if(etheridx == nelem(ethertab))
|
||||
sysfatal("too many interfaces");
|
||||
ethertab[etheridx++] = EARGF(usage());
|
||||
break;
|
||||
case 'i':
|
||||
lastc = 'i';
|
||||
c.iflag = 1;
|
||||
break;
|
||||
case 'r':
|
||||
lastc = 'r';
|
||||
c.flag |= Fraw;
|
||||
c.iflag = 1;
|
||||
break;
|
||||
case 's':
|
||||
lastc = 's';
|
||||
c.maxlba = sizetolba(getsize(EARGF(usage())));
|
||||
break;
|
||||
default:
|
||||
lastc = '?';
|
||||
usage();
|
||||
}ARGEND;
|
||||
|
||||
if(argc == 0 && lastc == 'e')
|
||||
break;
|
||||
if(argc == 0)
|
||||
usage();
|
||||
goblade(vblade + nblade++, *argv, &c);
|
||||
if(argc == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if(nblade == 0)
|
||||
usage();
|
||||
for(i = 0; i < etheridx; i++)
|
||||
mtutab[i] = getmtu(ethertab[i]);
|
||||
|
||||
launch(ethertab, efdtab);
|
||||
|
||||
for(; sleep(1*1000) != -1;)
|
||||
;
|
||||
threadexitsall("interrupted");
|
||||
}
|
Loading…
Reference in New Issue