* [9front] ethernet over gre @ 2023-09-23 14:26 Arne Meyer 2023-09-23 15:32 ` Jacob Moody 2023-09-23 19:50 ` Steve Simon 0 siblings, 2 replies; 7+ messages in thread From: Arne Meyer @ 2023-09-23 14:26 UTC (permalink / raw) To: 9front [-- Attachment #1: Type: text/plain, Size: 526 bytes --] Hello, i finally found the time to polish up my implementation of ethernet over gre for 9front. This is based on nusb/ether. It uses gre from the ip stack. I tested it with OpenBSD egre. For now only ipv4 is supported for the outside of the tunnel. 9front: ip address is 192.168.178.21 egre 192.168.178.20 ip/ipconfig -m 1400 ether /net/etherG0 10.0.0.1 255.255.255.0 OpenBSD: ifconfig egre0 create ifconfig egre0 tunnel 192.168.178.20 192.168.178.21 ifconfig egre0 10.0.0.2/24 mtu 1400 ifconfig egre0 up Greetings, Arne [-- Attachment #2.1: Type: text/plain, Size: 331 bytes --] from postmaster@9front: The following attachment had content that we can't prove to be harmless. To avoid possible automatic execution, we changed the content headers. The original header was: Content-Type: text/x-c; charset=UTF-8; name=egre.c Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename=egre.c [-- Attachment #2.2: egre.c.suspect --] [-- Type: application/octet-stream, Size: 14401 bytes --] #include <u.h> #include <libc.h> #include <thread.h> #include <libsec.h> //#include "usb.h" #include "dat.h" #include <fcall.h> #include <9p.h> #include <ip.h> typedef struct Tab Tab; typedef struct Dq Dq; typedef struct Conn Conn; typedef struct Stats Stats; enum { Qroot, Qiface, Qclone, Qstats, Qaddr, Qndir, Qctl, Qdata, Qtype, Qmax, }; struct Tab { char *name; ulong mode; }; Tab tab[] = { "/", DMDIR|0555, "etherG", DMDIR|0555, /* calling it *ether* makes snoopy(8) happy */ "clone", 0666, "stats", 0666, "addr", 0444, "%ud", DMDIR|0555, "ctl", 0666, "data", 0666, "type", 0444, }; struct Dq { QLock; Dq *next; Req *r; Req **rt; Block *q; Block **qt; int size; }; struct Conn { QLock; int used; int type; int prom; int bridge; int headersonly; Dq *dq; }; struct Stats { int in; int out; int bogus; }; uchar bcast[Eaddrlen] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; Stats stats; Conn conn[32]; int nconn = 0; int nprom = 0; int nmulti = 0; //Dev *epctl; //Dev *epin; //Dev *epout; ulong time0; static char *uname; #define PATH(type, n) ((type)|((n)<<8)) #define TYPE(path) (((uint)(path) & 0x000000FF)>>0) #define NUM(path) (((uint)(path) & 0xFFFFFF00)>>8) #define NUMCONN(c) (((uintptr)(c)-(uintptr)&conn[0])/sizeof(conn[0])) static void fillstat(Dir *d, uvlong path) { Tab *t; memset(d, 0, sizeof(*d)); d->uid = estrdup9p(uname); d->gid = estrdup9p(uname); d->qid.path = path; d->atime = d->mtime = time0; t = &tab[TYPE(path)]; d->name = smprint(t->name, NUM(path)); d->qid.type = t->mode>>24; d->mode = t->mode; } static void fsattach(Req *r) { if(r->ifcall.aname && r->ifcall.aname[0]){ respond(r, "invalid attach specifier"); return; } if(uname == nil) uname = estrdup9p(r->ifcall.uname); r->fid->qid.path = PATH(Qroot, 0); r->fid->qid.type = QTDIR; r->fid->qid.vers = 0; r->ofcall.qid = r->fid->qid; respond(r, nil); } static void fsstat(Req *r) { fillstat(&r->d, r->fid->qid.path); respond(r, nil); } static int rootgen(int i, Dir *d, void*) { i += Qroot+1; if(i == Qiface){ fillstat(d, i); return 0; } return -1; } static int ifacegen(int i, Dir *d, void*) { i += Qiface+1; if(i < Qndir){ fillstat(d, i); return 0; } i -= Qndir; if(i < nconn){ fillstat(d, PATH(Qndir, i)); return 0; } return -1; } static int ndirgen(int i, Dir *d, void *aux) { i += Qndir+1; if(i < Qmax){ fillstat(d, PATH(i, NUMCONN(aux))); return 0; } return -1; } static char* fswalk1(Fid *fid, char *name, Qid *qid) { int i, n; char buf[32]; ulong path; path = fid->qid.path; if(!(fid->qid.type&QTDIR)) return "walk in non-directory"; if(strcmp(name, "..") == 0){ switch(TYPE(path)){ case Qroot: return nil; case Qiface: qid->path = PATH(Qroot, 0); qid->type = tab[Qroot].mode>>24; return nil; case Qndir: qid->path = PATH(Qiface, 0); qid->type = tab[Qiface].mode>>24; return nil; default: return "bug in fswalk1"; } } for(i = TYPE(path)+1; i<nelem(tab); i++){ if(i==Qndir){ n = atoi(name); snprint(buf, sizeof buf, "%d", n); if(n < nconn && strcmp(buf, name) == 0){ qid->path = PATH(i, n); qid->type = tab[i].mode>>24; return nil; } break; } if(strcmp(name, tab[i].name) == 0){ qid->path = PATH(i, NUM(path)); qid->type = tab[i].mode>>24; return nil; } if(tab[i].mode&DMDIR) break; } return "directory entry not found"; } static void matchrq(Dq *d) { Req *r; Block *b; while(r = d->r){ int n; if((b = d->q) == nil) break; d->size -= BLEN(b); if((d->q = b->next) == nil) d->qt = &d->q; if((d->r = (Req*)r->aux) == nil) d->rt = &d->r; n = r->ifcall.count; if(n > BLEN(b)) n = BLEN(b); memmove(r->ofcall.data, b->rp, n); r->ofcall.count = n; freeb(b); respond(r, nil); } } static void readconndata(Req *r) { Dq *d; d = r->fid->aux; qlock(d); r->aux = nil; *d->rt = r; d->rt = (Req**)&r->aux; matchrq(d); qunlock(d); } static void etheroq(Block*, Conn*); static void writeconndata(Req *r) { void *p; int n; Block *b; p = r->ifcall.data; n = r->ifcall.count; /* minimum frame length for rtl8150 */ if(n < 60) n = 60; /* slack space for header and trailers */ n += 44+16; b = allocb(n); /* header space */ b->wp += 44; b->rp = b->wp; /* copy in the ethernet packet */ memmove(b->wp, p, r->ifcall.count); b->wp += r->ifcall.count; etheroq(b, &conn[NUM(r->fid->qid.path)]); r->ofcall.count = r->ifcall.count; respond(r, nil); } static void fsread(Req *r) { char buf[200]; char e[ERRMAX]; ulong path; path = r->fid->qid.path; switch(TYPE(path)){ default: snprint(e, sizeof e, "bug in fsread path=%lux", path); respond(r, e); break; case Qroot: dirread9p(r, rootgen, nil); respond(r, nil); break; case Qiface: dirread9p(r, ifacegen, nil); respond(r, nil); break; case Qstats: snprint(buf, sizeof(buf), "in: %d\n" "out: %d\n" "bogus: %d\n" "mbps: %d\n" "addr: %E\n", stats.in, stats.out, stats.bogus, 10, macaddr); readstr(r, buf); respond(r, nil); break; case Qaddr: snprint(buf, sizeof(buf), "%E", macaddr); readstr(r, buf); respond(r, nil); break; case Qndir: dirread9p(r, ndirgen, &conn[NUM(path)]); respond(r, nil); break; case Qctl: snprint(buf, sizeof(buf), "%11d ", NUM(path)); readstr(r, buf); respond(r, nil); break; case Qtype: snprint(buf, sizeof(buf), "%11d ", conn[NUM(path)].type); readstr(r, buf); respond(r, nil); break; case Qdata: readconndata(r); break; } } static int activemulti(uchar *ea) { int i; for(i=0; i<nmulti; i++) if(memcmp(ea, multiaddr[i], Eaddrlen) == 0) return i; return -1; } static void fswrite(Req *r) { char e[ERRMAX]; ulong path; char *p; int n; path = r->fid->qid.path; switch(TYPE(path)){ case Qctl: n = r->ifcall.count; p = (char*)r->ifcall.data; if(n >= 6 && memcmp(p, "bridge", 6)==0){ conn[NUM(path)].bridge = 1; } else if(n >= 11 && memcmp(p, "headersonly", 11)==0){ conn[NUM(path)].headersonly = 1; } else if(n >= 11 && memcmp(p, "promiscuous", 11)==0){ if(conn[NUM(path)].prom == 0){ conn[NUM(path)].prom = 1; //if(nprom++ == 0 && eppromiscuous != nil) //(*eppromiscuous)(epctl, 1); } } else if(n >= 9+12 && (memcmp(p, "addmulti ", 9)==0 || memcmp(p, "remmulti ", 9)==0)){ uchar ea[Eaddrlen]; int i; if(parseether(ea, p+9) < 0){ respond(r, "bad ether address"); return; } i = activemulti(ea); if(i >= 0){ if(*p == 'r'){ memmove(multiaddr[i], multiaddr[--nmulti], Eaddrlen); //if(epmulticast != nil) // (*epmulticast)(epctl, ea, 0); } } else if(nmulti < nelem(multiaddr)){ if(*p == 'a'){ memmove(multiaddr[nmulti++], ea, Eaddrlen); //if(epmulticast != nil) // (*epmulticast)(epctl, ea, 1); } } } else if(n > 8 && memcmp(p, "connect ", 8)==0){ char x[12]; if(n - 8 >= sizeof(x)){ respond(r, "invalid control msg"); return; } p += 8; memcpy(x, p, n-8); x[n-8] = 0; conn[NUM(path)].type = strtoul(x, nil, 0); } r->ofcall.count = n; respond(r, nil); break; case Qdata: writeconndata(r); break; default: snprint(e, sizeof e, "bug in fswrite path=%lux", path); respond(r, e); } } static void fsopen(Req *r) { static int need[4] = { 4, 2, 6, 1 }; ulong path; int i, n; Tab *t; Dq *d; Conn *c; /* * lib9p already handles the blatantly obvious. * we just have to enforce the permissions we have set. */ path = r->fid->qid.path; t = &tab[TYPE(path)]; n = need[r->ifcall.mode&3]; if((n&t->mode) != n){ respond(r, "permission denied"); return; } d = nil; r->fid->aux = nil; switch(TYPE(path)){ case Qclone: for(i=0; i<nelem(conn); i++){ if(conn[i].used) continue; if(i >= nconn) nconn = i+1; path = PATH(Qctl, i); goto CaseConn; } respond(r, "out of connections"); return; case Qdata: d = emalloc9p(sizeof(*d)); memset(d, 0, sizeof(*d)); d->qt = &d->q; d->rt = &d->r; r->fid->aux = d; case Qndir: case Qctl: case Qtype: CaseConn: c = &conn[NUM(path)]; qlock(c); if(c->used++ == 0){ c->type = 0; c->prom = 0; c->bridge = 0; c->headersonly = 0; } if(d != nil){ d->next = c->dq; c->dq = d; } qunlock(c); break; } r->fid->qid.path = path; r->ofcall.qid.path = path; respond(r, nil); } static void fsflush(Req *r) { Req *o, **p; Fid *f; Dq *d; o = r->oldreq; f = o->fid; if(TYPE(f->qid.path) == Qdata){ d = f->aux; qlock(d); for(p=&d->r; *p; p=(Req**)&((*p)->aux)){ if(*p == o){ if((*p = (Req*)o->aux) == nil) d->rt = p; r->oldreq = nil; respond(o, "interrupted"); break; } } qunlock(d); } respond(r, nil); } static void fsdestroyfid(Fid *fid) { Conn *c; Dq **x, *d; Block *b; if(TYPE(fid->qid.path) >= Qndir){ c = &conn[NUM(fid->qid.path)]; qlock(c); if(d = fid->aux){ fid->aux = nil; for(x=&c->dq; *x; x=&((*x)->next)){ if(*x == d){ *x = d->next; break; } } while(b = d->q){ d->q = b->next; freeb(b); } free(d); } if(TYPE(fid->qid.path) == Qctl){ if(c->prom){ c->prom = 0; //if(--nprom == 0 && eppromiscuous != nil) // (*eppromiscuous)(epctl, 0); } } if(TYPE(fid->qid.path) == Qdata && c->bridge) memset(mactab, 0, sizeof(mactab)); c->used--; qunlock(c); } } static int inote(void *, char *msg) { if(strstr(msg, "interrupt")) return 1; return 0; } static void cpass(Conn *c, Block *bp) { Dq *d; qlock(c); for(d = c->dq; d != nil; d = d->next){ qlock(d); if(d->size < 100000){ Block *q; if(d->next == nil) { q = bp; bp = nil; } else q = copyblock(bp, BLEN(bp)); q->next = nil; *d->qt = q; d->qt = &q->next; d->size += BLEN(q); matchrq(d); } qunlock(d); } qunlock(c); if(bp != nil) freeb(bp); } static void etherrtrace(Conn *c, Etherpkt *pkt, int len) { Block *bp; bp = allocb(64); memmove(bp->wp, pkt, len < 64 ? len : 64); if(c->type != -2){ u32int ms = nsec()/1000000LL; bp->wp[58] = len>>8; bp->wp[59] = len; bp->wp[60] = ms>>24; bp->wp[61] = ms>>16; bp->wp[62] = ms>>8; bp->wp[63] = ms; } bp->wp += 64; cpass(c, bp); } static Macent* macent(uchar *ea) { u32int h = (ea[0] | ea[1]<<8 | ea[2]<<16 | ea[3]<<24) ^ (ea[4] | ea[5]<<8); return &mactab[h % nelem(mactab)]; } static Block* ethermux(Block *bp, Conn *from) { Etherpkt *pkt; Conn *c, *x; int len, multi, tome, port, type, dispose; len = BLEN(bp); if(len < ETHERHDRSIZE) goto Drop; pkt = (Etherpkt*)bp->rp; if(!(multi = pkt->d[0] & 1)){ tome = memcmp(pkt->d, macaddr, Eaddrlen) == 0; if(!tome && from != nil && nprom == 0) return bp; } else { tome = 0; if(from == nil && nprom == 0 && memcmp(pkt->d, bcast, Eaddrlen) != 0 && activemulti(pkt->d) < 0) goto Drop; } port = -1; if(nprom){ if((from == nil || from->bridge) && (pkt->s[0] & 1) == 0){ Macent *t = macent(pkt->s); t->port = from == nil ? 0 : 1+(from - conn); memmove(t->ea, pkt->s, Eaddrlen); } if(!tome && !multi){ Macent *t = macent(pkt->d); if(memcmp(t->ea, pkt->d, Eaddrlen) == 0) port = t->port; } } x = nil; type = (pkt->type[0]<<8)|pkt->type[1]; dispose = tome || from == nil || port > 0; for(c = conn; c < &conn[nconn]; c++){ if(!c->used) continue; if(c->type != type && c->type >= 0) continue; if(!tome && !multi && !c->prom) continue; if(c->bridge){ if(tome || c == from) continue; if(port >= 0 && port != 1+(c - conn)) continue; } if(c->headersonly || c->type == -2){ etherrtrace(c, pkt, len); continue; } if(dispose && x == nil) x = c; else cpass(c, copyblock(bp, len)); } if(x != nil){ cpass(x, bp); return nil; } if(dispose){ Drop: freeb(bp); return nil; } return bp; } void etheriq(Block *bp) { stats.in++; ethermux(bp, nil); } static void etheroq(Block *bp, Conn *from) { if(!from->bridge) memmove(((Etherpkt*)bp->rp)->s, macaddr, Eaddrlen); bp = ethermux(bp, from); if(bp == nil) return; stats.out++; /* transmit frees buffer */ bp->rp-=12; memset(bp->rp, 0, 12); write(grecon, bp->rp, BLEN(bp)); freeb(bp); } static void grereadproc(void *) { char err[ERRMAX]; uchar buf[1600]; int nerr; int len; Block *b; ushort flags; atnotify(inote, 1); threadsetname("grereadproc"); nerr = 0; for(;;){ /* receive allocates buffer and calls etheriq(b, 1); */ if((len = read(grecon, buf, 1600)) < 0){ fprint(2, "got packet!\n"); rerrstr(err, sizeof(err)); if(strstr(err, "interrupted") || strstr(err, "timed out")) continue; fprint(2, "grereadproc: %s\n", err); if(++nerr < 3) continue; threadexitsall(err); } nerr = 0; flags = nhgets(buf+8); if(flags){ stats.bogus++; continue; } b = allocb(1600); memcpy(b->wp, buf+12, len-12); b->wp+=(len-12); etheriq(b); } } Srv fs = { .attach= fsattach, .destroyfid= fsdestroyfid, .walk1= fswalk1, .open= fsopen, .read= fsread, .write= fswrite, .stat= fsstat, .flush= fsflush, }; static void usage(void) { fprint(2, "usage: %s [-dD] [-i index] [-a addr] remote\n", argv0); exits("usage"); } void threadmain(int argc, char **argv) { char s[64], *t, *d; int idx = 0; fmtinstall('E', eipfmt); ARGBEGIN { case 'd': debug = 1; break; case 'D': chatty9p++; break; case 'i': idx = atoi(EARGF(usage())); case 'a': setmac = 1; if(parseether(macaddr, EARGF(usage())) != 0) usage(); break; default: usage(); } ARGEND; if(argc != 1) usage(); if(!setmac){ genrandom(macaddr, Eaddrlen); macaddr[0] &= 0xfe; } d = smprint("gre!%s!25944", argv[0]); grecon = dial(d, nil, nil, nil); if(grecon == -1) sysfatal("%r"); werrstr(""); proccreate(grereadproc, nil, 8*1024); atnotify(inote, 1); time0 = time(0); tab[Qiface].name = smprint("etherG%d", idx); snprint(s, sizeof(s), "%d.ugre", idx); threadpostmountsrv(&fs, s, "/net/", MAFTER); threadexits(0); } Block* allocb(int size) { Block *b; b = emalloc9p(sizeof(*b) + size); b->lim = b->base + size; b->rp = b->base; b->wp = b->base; b->next = nil; return b; } Block* copyblock(Block *b, int count) { Block *nb; if(count > BLEN(b)) count = BLEN(b); nb = allocb(count); memmove(nb->wp, b->rp, count); nb->wp += count; return nb; } ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [9front] ethernet over gre 2023-09-23 14:26 [9front] ethernet over gre Arne Meyer @ 2023-09-23 15:32 ` Jacob Moody 2023-09-23 15:46 ` Arne Meyer 2023-09-23 19:50 ` Steve Simon 1 sibling, 1 reply; 7+ messages in thread From: Jacob Moody @ 2023-09-23 15:32 UTC (permalink / raw) To: 9front This is pretty cool, could you write up a man page for it perhaps? Thanks, Jacob Moody On 9/23/23 09:26, Arne Meyer wrote: > Hello, > > i finally found the time to polish up my implementation of ethernet over gre for 9front. > This is based on nusb/ether. It uses gre from the ip stack. I tested it with OpenBSD egre. > For now only ipv4 is supported for the outside of the tunnel. > > 9front: > ip address is 192.168.178.21 > > egre 192.168.178.20 > ip/ipconfig -m 1400 ether /net/etherG0 10.0.0.1 255.255.255.0 > > OpenBSD: > > ifconfig egre0 create > ifconfig egre0 tunnel 192.168.178.20 192.168.178.21 > ifconfig egre0 10.0.0.2/24 mtu 1400 > ifconfig egre0 up > > Greetings, > Arne > > > from postmaster@9front: > The following attachment had content that we can't > prove to be harmless. To avoid possible automatic > execution, we changed the content headers. > The original header was: > > Content-Type: text/x-c; charset=UTF-8; name=egre.c > Content-Transfer-Encoding: base64 > Content-Disposition: attachment; filename=egre.c ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [9front] ethernet over gre 2023-09-23 15:32 ` Jacob Moody @ 2023-09-23 15:46 ` Arne Meyer 2023-09-23 15:56 ` Jacob Moody 0 siblings, 1 reply; 7+ messages in thread From: Arne Meyer @ 2023-09-23 15:46 UTC (permalink / raw) To: 9front I have no clue how to write a man page but I'll give it a try for sure! > Jacob Moody <moody@posixcafe.org> hat am 23.09.2023 17:32 CEST geschrieben: > > > This is pretty cool, could you write up a man page for it perhaps? > > Thanks, > Jacob Moody > > On 9/23/23 09:26, Arne Meyer wrote: > > Hello, > > > > i finally found the time to polish up my implementation of ethernet over gre for 9front. > > This is based on nusb/ether. It uses gre from the ip stack. I tested it with OpenBSD egre. > > For now only ipv4 is supported for the outside of the tunnel. > > > > 9front: > > ip address is 192.168.178.21 > > > > egre 192.168.178.20 > > ip/ipconfig -m 1400 ether /net/etherG0 10.0.0.1 255.255.255.0 > > > > OpenBSD: > > > > ifconfig egre0 create > > ifconfig egre0 tunnel 192.168.178.20 192.168.178.21 > > ifconfig egre0 10.0.0.2/24 mtu 1400 > > ifconfig egre0 up > > > > Greetings, > > Arne > > > > > > from postmaster@9front: > > The following attachment had content that we can't > > prove to be harmless. To avoid possible automatic > > execution, we changed the content headers. > > The original header was: > > > > Content-Type: text/x-c; charset=UTF-8; name=egre.c > > Content-Transfer-Encoding: base64 > > Content-Disposition: attachment; filename=egre.c ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [9front] ethernet over gre 2023-09-23 15:46 ` Arne Meyer @ 2023-09-23 15:56 ` Jacob Moody 2023-09-23 20:33 ` Arne Meyer 0 siblings, 1 reply; 7+ messages in thread From: Jacob Moody @ 2023-09-23 15:56 UTC (permalink / raw) To: 9front My advice is to read around the other man pages to get a broad idea of the format, and if you have any questions about what a macro specifically does man(6) explains them all in more detail. That's how I learned anyway. Feel free to ask if you run in to any issues. Thanks! moody On 9/23/23 10:46, Arne Meyer wrote: > I have no clue how to write a man page but I'll give it a try for sure! > >> Jacob Moody <moody@posixcafe.org> hat am 23.09.2023 17:32 CEST geschrieben: >> >> >> This is pretty cool, could you write up a man page for it perhaps? >> >> Thanks, >> Jacob Moody >> >> On 9/23/23 09:26, Arne Meyer wrote: >>> Hello, >>> >>> i finally found the time to polish up my implementation of ethernet over gre for 9front. >>> This is based on nusb/ether. It uses gre from the ip stack. I tested it with OpenBSD egre. >>> For now only ipv4 is supported for the outside of the tunnel. >>> >>> 9front: >>> ip address is 192.168.178.21 >>> >>> egre 192.168.178.20 >>> ip/ipconfig -m 1400 ether /net/etherG0 10.0.0.1 255.255.255.0 >>> >>> OpenBSD: >>> >>> ifconfig egre0 create >>> ifconfig egre0 tunnel 192.168.178.20 192.168.178.21 >>> ifconfig egre0 10.0.0.2/24 mtu 1400 >>> ifconfig egre0 up >>> >>> Greetings, >>> Arne >>> >>> >>> from postmaster@9front: >>> The following attachment had content that we can't >>> prove to be harmless. To avoid possible automatic >>> execution, we changed the content headers. >>> The original header was: >>> >>> Content-Type: text/x-c; charset=UTF-8; name=egre.c >>> Content-Transfer-Encoding: base64 >>> Content-Disposition: attachment; filename=egre.c ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [9front] ethernet over gre 2023-09-23 15:56 ` Jacob Moody @ 2023-09-23 20:33 ` Arne Meyer 0 siblings, 0 replies; 7+ messages in thread From: Arne Meyer @ 2023-09-23 20:33 UTC (permalink / raw) To: 9front [-- Attachment #1: Type: text/plain, Size: 1851 bytes --] Here is a patch for 9front with my first try for a man page. > Jacob Moody <moody@posixcafe.org> hat am 23.09.2023 17:56 CEST geschrieben: > > > My advice is to read around the other man pages to get a broad idea of the format, > and if you have any questions about what a macro specifically does man(6) explains them > all in more detail. That's how I learned anyway. Feel free to ask if you run in to any issues. > > Thanks! > moody > > On 9/23/23 10:46, Arne Meyer wrote: > > I have no clue how to write a man page but I'll give it a try for sure! > > > >> Jacob Moody <moody@posixcafe.org> hat am 23.09.2023 17:32 CEST geschrieben: > >> > >> > >> This is pretty cool, could you write up a man page for it perhaps? > >> > >> Thanks, > >> Jacob Moody > >> > >> On 9/23/23 09:26, Arne Meyer wrote: > >>> Hello, > >>> > >>> i finally found the time to polish up my implementation of ethernet over gre for 9front. > >>> This is based on nusb/ether. It uses gre from the ip stack. I tested it with OpenBSD egre. > >>> For now only ipv4 is supported for the outside of the tunnel. > >>> > >>> 9front: > >>> ip address is 192.168.178.21 > >>> > >>> egre 192.168.178.20 > >>> ip/ipconfig -m 1400 ether /net/etherG0 10.0.0.1 255.255.255.0 > >>> > >>> OpenBSD: > >>> > >>> ifconfig egre0 create > >>> ifconfig egre0 tunnel 192.168.178.20 192.168.178.21 > >>> ifconfig egre0 10.0.0.2/24 mtu 1400 > >>> ifconfig egre0 up > >>> > >>> Greetings, > >>> Arne > >>> > >>> > >>> from postmaster@9front: > >>> The following attachment had content that we can't > >>> prove to be harmless. To avoid possible automatic > >>> execution, we changed the content headers. > >>> The original header was: > >>> > >>> Content-Type: text/x-c; charset=UTF-8; name=egre.c > >>> Content-Transfer-Encoding: base64 > >>> Content-Disposition: attachment; filename=egre.c [-- Attachment #2: egre.patch --] [-- Type: application/octet-stream, Size: 17182 bytes --] diff 44a2f89a03c370940fa0f4747c2357c73984d653 uncommitted --- /dev/null +++ b/./sys/man/8/egre @@ -1,0 +1,42 @@ +.TH egre 8 +.SH NAME +egre \- ethernet over gre +.SH SYNOPSYS +.B ip/egre +[ +.B -ai +] [ +.B -a +.I mac +] [ +.B -i +.I index +] +.I remote +.SH DESCRIPTION +GRE is a tunneling protocol that can encapsulate a variety of network protocols inside an ip tunnel. +.I egre +creates an ethernet connection over ip to a remote host. The file system provided is compatible with ether(3) and is bound after /net so the device will appear as /net/etherGN. +.PP +With no option +.I egre +creates an ethernet tunnel to +.I remote +with a random source mac and binds to /net/etherG0. +.PP +.I Egre +supports the following options: +.TP 3 +.B a +set the source mac address +.TP +.B i +set the interface to /net/etherG[index] +.SH SOURCE +.B /sys/src/cmp/ip/egre.c +.SH SEE ALSO +.IR ipconfig (8), +.I gre +in +.IR ip(3) + --- /dev/null +++ b/./sys/src/cmd/ip/egre.c @@ -1,0 +1,952 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include <libsec.h> + +#include <fcall.h> +#include <9p.h> +#include <ip.h> + +typedef struct Tab Tab; +typedef struct Dq Dq; +typedef struct Conn Conn; +typedef struct Stats Stats; + +typedef struct Block Block; +struct Block +{ + Block *next; + + uchar *rp; + uchar *wp; + uchar *lim; + + uchar base[]; +}; + +#define BLEN(s) ((s)->wp - (s)->rp) + +Block* allocb(int size); +Block* copyblock(Block*, int); +#define freeb(b) free(b) + +enum { + Eaddrlen= 6, + ETHERHDRSIZE= 14, /* size of an ethernet header */ + Maxpkt= 2000, +}; + +typedef struct Macent Macent; +struct Macent +{ + uchar ea[Eaddrlen]; + ushort port; +}; + +typedef struct Etherpkt Etherpkt; +struct Etherpkt +{ + uchar d[Eaddrlen]; + uchar s[Eaddrlen]; + uchar type[2]; + uchar data[1500]; +}; + +enum +{ + Cdcunion = 6, + Scether = 6, + Fnether = 15, +}; + +int debug; +int setmac; + +int nprom; +int nmulti; +uchar multiaddr[32][Eaddrlen]; + +/* to be filled in by *init() */ +uchar macaddr[Eaddrlen]; + +Macent mactab[127]; + +int grecon; +int grectl; + +void etheriq(Block*); + + +enum +{ + Qroot, + Qiface, + Qclone, + Qstats, + Qaddr, + Qndir, + Qctl, + Qdata, + Qtype, + Qmax, +}; + +struct Tab +{ + char *name; + ulong mode; +}; + +Tab tab[] = +{ + "/", DMDIR|0555, + "etherG", DMDIR|0555, /* calling it *ether* makes snoopy(8) happy */ + "clone", 0666, + "stats", 0666, + "addr", 0444, + "%ud", DMDIR|0555, + "ctl", 0666, + "data", 0666, + "type", 0444, +}; + +struct Dq +{ + QLock; + + Dq *next; + Req *r; + Req **rt; + Block *q; + Block **qt; + + int size; +}; + +struct Conn +{ + QLock; + + int used; + int type; + int prom; + int bridge; + int headersonly; + + Dq *dq; +}; + +struct Stats +{ + int in; + int out; + int bogus; +}; + +uchar bcast[Eaddrlen] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + +Stats stats; +Conn conn[32]; +int nconn = 0; + +int nprom = 0; +int nmulti = 0; + +ulong time0; +static char *uname; + +#define PATH(type, n) ((type)|((n)<<8)) +#define TYPE(path) (((uint)(path) & 0x000000FF)>>0) +#define NUM(path) (((uint)(path) & 0xFFFFFF00)>>8) +#define NUMCONN(c) (((uintptr)(c)-(uintptr)&conn[0])/sizeof(conn[0])) + +static void +fillstat(Dir *d, uvlong path) +{ + Tab *t; + + memset(d, 0, sizeof(*d)); + d->uid = estrdup9p(uname); + d->gid = estrdup9p(uname); + d->qid.path = path; + d->atime = d->mtime = time0; + t = &tab[TYPE(path)]; + d->name = smprint(t->name, NUM(path)); + d->qid.type = t->mode>>24; + d->mode = t->mode; +} + +static void +fsattach(Req *r) +{ + if(r->ifcall.aname && r->ifcall.aname[0]){ + respond(r, "invalid attach specifier"); + return; + } + if(uname == nil) + uname = estrdup9p(r->ifcall.uname); + r->fid->qid.path = PATH(Qroot, 0); + r->fid->qid.type = QTDIR; + r->fid->qid.vers = 0; + r->ofcall.qid = r->fid->qid; + respond(r, nil); +} + +static void +fsstat(Req *r) +{ + fillstat(&r->d, r->fid->qid.path); + respond(r, nil); +} + +static int +rootgen(int i, Dir *d, void*) +{ + i += Qroot+1; + if(i == Qiface){ + fillstat(d, i); + return 0; + } + return -1; +} + +static int +ifacegen(int i, Dir *d, void*) +{ + i += Qiface+1; + if(i < Qndir){ + fillstat(d, i); + return 0; + } + i -= Qndir; + if(i < nconn){ + fillstat(d, PATH(Qndir, i)); + return 0; + } + return -1; +} + +static int +ndirgen(int i, Dir *d, void *aux) +{ + i += Qndir+1; + if(i < Qmax){ + fillstat(d, PATH(i, NUMCONN(aux))); + return 0; + } + return -1; +} + +static char* +fswalk1(Fid *fid, char *name, Qid *qid) +{ + int i, n; + char buf[32]; + ulong path; + + path = fid->qid.path; + if(!(fid->qid.type&QTDIR)) + return "walk in non-directory"; + + if(strcmp(name, "..") == 0){ + switch(TYPE(path)){ + case Qroot: + return nil; + case Qiface: + qid->path = PATH(Qroot, 0); + qid->type = tab[Qroot].mode>>24; + return nil; + case Qndir: + qid->path = PATH(Qiface, 0); + qid->type = tab[Qiface].mode>>24; + return nil; + default: + return "bug in fswalk1"; + } + } + + for(i = TYPE(path)+1; i<nelem(tab); i++){ + if(i==Qndir){ + n = atoi(name); + snprint(buf, sizeof buf, "%d", n); + if(n < nconn && strcmp(buf, name) == 0){ + qid->path = PATH(i, n); + qid->type = tab[i].mode>>24; + return nil; + } + break; + } + if(strcmp(name, tab[i].name) == 0){ + qid->path = PATH(i, NUM(path)); + qid->type = tab[i].mode>>24; + return nil; + } + if(tab[i].mode&DMDIR) + break; + } + return "directory entry not found"; +} + +static void +matchrq(Dq *d) +{ + Req *r; + Block *b; + + while(r = d->r){ + int n; + + if((b = d->q) == nil) + break; + + d->size -= BLEN(b); + if((d->q = b->next) == nil) + d->qt = &d->q; + if((d->r = (Req*)r->aux) == nil) + d->rt = &d->r; + + n = r->ifcall.count; + if(n > BLEN(b)) + n = BLEN(b); + memmove(r->ofcall.data, b->rp, n); + r->ofcall.count = n; + freeb(b); + + respond(r, nil); + } +} + +static void +readconndata(Req *r) +{ + Dq *d; + + d = r->fid->aux; + qlock(d); + r->aux = nil; + *d->rt = r; + d->rt = (Req**)&r->aux; + matchrq(d); + qunlock(d); +} + +static void +etheroq(Block*, Conn*); + +static void +writeconndata(Req *r) +{ + void *p; + int n; + Block *b; + + p = r->ifcall.data; + n = r->ifcall.count; + + /* minimum frame length for rtl8150 */ + if(n < 60) + n = 60; + + /* slack space for header and trailers */ + n += 44+16; + + b = allocb(n); + + /* header space */ + b->wp += 44; + b->rp = b->wp; + + /* copy in the ethernet packet */ + memmove(b->wp, p, r->ifcall.count); + b->wp += r->ifcall.count; + + etheroq(b, &conn[NUM(r->fid->qid.path)]); + + r->ofcall.count = r->ifcall.count; + respond(r, nil); +} + +static void +fsread(Req *r) +{ + char buf[200]; + char e[ERRMAX]; + ulong path; + + path = r->fid->qid.path; + + switch(TYPE(path)){ + default: + snprint(e, sizeof e, "bug in fsread path=%lux", path); + respond(r, e); + break; + + case Qroot: + dirread9p(r, rootgen, nil); + respond(r, nil); + break; + + case Qiface: + dirread9p(r, ifacegen, nil); + respond(r, nil); + break; + + case Qstats: + snprint(buf, sizeof(buf), + "in: %d\n" + "out: %d\n" + "bogus: %d\n" + "mbps: %d\n" + "addr: %E\n", + stats.in, stats.out, stats.bogus, 10, macaddr); + readstr(r, buf); + respond(r, nil); + break; + + case Qaddr: + snprint(buf, sizeof(buf), "%E", macaddr); + readstr(r, buf); + respond(r, nil); + break; + + case Qndir: + dirread9p(r, ndirgen, &conn[NUM(path)]); + respond(r, nil); + break; + + case Qctl: + snprint(buf, sizeof(buf), "%11d ", NUM(path)); + readstr(r, buf); + respond(r, nil); + break; + + case Qtype: + snprint(buf, sizeof(buf), "%11d ", conn[NUM(path)].type); + readstr(r, buf); + respond(r, nil); + break; + + case Qdata: + readconndata(r); + break; + } +} + +static int +activemulti(uchar *ea) +{ + int i; + + for(i=0; i<nmulti; i++) + if(memcmp(ea, multiaddr[i], Eaddrlen) == 0) + return i; + return -1; +} + +static void +fswrite(Req *r) +{ + char e[ERRMAX]; + ulong path; + char *p; + int n; + + path = r->fid->qid.path; + switch(TYPE(path)){ + case Qctl: + n = r->ifcall.count; + p = (char*)r->ifcall.data; + if(n >= 6 && memcmp(p, "bridge", 6)==0){ + conn[NUM(path)].bridge = 1; + } else if(n >= 11 && memcmp(p, "headersonly", 11)==0){ + conn[NUM(path)].headersonly = 1; + } else if(n >= 11 && memcmp(p, "promiscuous", 11)==0){ + if(conn[NUM(path)].prom == 0){ + conn[NUM(path)].prom = 1; + //if(nprom++ == 0 && eppromiscuous != nil) + //(*eppromiscuous)(epctl, 1); + } + } else if(n >= 9+12 && (memcmp(p, "addmulti ", 9)==0 || memcmp(p, "remmulti ", 9)==0)){ + uchar ea[Eaddrlen]; + int i; + + if(parseether(ea, p+9) < 0){ + respond(r, "bad ether address"); + return; + } + i = activemulti(ea); + if(i >= 0){ + if(*p == 'r'){ + memmove(multiaddr[i], multiaddr[--nmulti], Eaddrlen); + //if(epmulticast != nil) + // (*epmulticast)(epctl, ea, 0); + } + } else if(nmulti < nelem(multiaddr)){ + if(*p == 'a'){ + memmove(multiaddr[nmulti++], ea, Eaddrlen); + //if(epmulticast != nil) + // (*epmulticast)(epctl, ea, 1); + } + } + } else if(n > 8 && memcmp(p, "connect ", 8)==0){ + char x[12]; + + if(n - 8 >= sizeof(x)){ + respond(r, "invalid control msg"); + return; + } + + p += 8; + memcpy(x, p, n-8); + x[n-8] = 0; + + conn[NUM(path)].type = strtoul(x, nil, 0); + } + r->ofcall.count = n; + respond(r, nil); + break; + case Qdata: + writeconndata(r); + break; + default: + snprint(e, sizeof e, "bug in fswrite path=%lux", path); + respond(r, e); + } +} + +static void +fsopen(Req *r) +{ + static int need[4] = { 4, 2, 6, 1 }; + ulong path; + int i, n; + Tab *t; + Dq *d; + Conn *c; + + /* + * lib9p already handles the blatantly obvious. + * we just have to enforce the permissions we have set. + */ + path = r->fid->qid.path; + t = &tab[TYPE(path)]; + n = need[r->ifcall.mode&3]; + if((n&t->mode) != n){ + respond(r, "permission denied"); + return; + } + + d = nil; + r->fid->aux = nil; + + switch(TYPE(path)){ + case Qclone: + for(i=0; i<nelem(conn); i++){ + if(conn[i].used) + continue; + if(i >= nconn) + nconn = i+1; + path = PATH(Qctl, i); + goto CaseConn; + } + respond(r, "out of connections"); + return; + case Qdata: + d = emalloc9p(sizeof(*d)); + memset(d, 0, sizeof(*d)); + d->qt = &d->q; + d->rt = &d->r; + r->fid->aux = d; + case Qndir: + case Qctl: + case Qtype: + CaseConn: + c = &conn[NUM(path)]; + qlock(c); + if(c->used++ == 0){ + c->type = 0; + c->prom = 0; + c->bridge = 0; + c->headersonly = 0; + } + if(d != nil){ + d->next = c->dq; + c->dq = d; + } + qunlock(c); + break; + } + + r->fid->qid.path = path; + r->ofcall.qid.path = path; + respond(r, nil); +} + +static void +fsflush(Req *r) +{ + Req *o, **p; + Fid *f; + Dq *d; + + o = r->oldreq; + f = o->fid; + if(TYPE(f->qid.path) == Qdata){ + d = f->aux; + qlock(d); + for(p=&d->r; *p; p=(Req**)&((*p)->aux)){ + if(*p == o){ + if((*p = (Req*)o->aux) == nil) + d->rt = p; + r->oldreq = nil; + respond(o, "interrupted"); + break; + } + } + qunlock(d); + } + respond(r, nil); +} + + +static void +fsdestroyfid(Fid *fid) +{ + Conn *c; + Dq **x, *d; + Block *b; + + if(TYPE(fid->qid.path) >= Qndir){ + c = &conn[NUM(fid->qid.path)]; + qlock(c); + if(d = fid->aux){ + fid->aux = nil; + for(x=&c->dq; *x; x=&((*x)->next)){ + if(*x == d){ + *x = d->next; + break; + } + } + while(b = d->q){ + d->q = b->next; + freeb(b); + } + free(d); + } + if(TYPE(fid->qid.path) == Qctl){ + if(c->prom){ + c->prom = 0; + //if(--nprom == 0 && eppromiscuous != nil) + // (*eppromiscuous)(epctl, 0); + } + } + if(TYPE(fid->qid.path) == Qdata && c->bridge) + memset(mactab, 0, sizeof(mactab)); + c->used--; + qunlock(c); + } +} + +static int +inote(void *, char *msg) +{ + if(strstr(msg, "interrupt")) + return 1; + return 0; +} + +static void +cpass(Conn *c, Block *bp) +{ + Dq *d; + + qlock(c); + for(d = c->dq; d != nil; d = d->next){ + qlock(d); + if(d->size < 100000){ + Block *q; + + if(d->next == nil) { + q = bp; + bp = nil; + } else + q = copyblock(bp, BLEN(bp)); + q->next = nil; + *d->qt = q; + d->qt = &q->next; + d->size += BLEN(q); + matchrq(d); + } + qunlock(d); + } + qunlock(c); + + if(bp != nil) + freeb(bp); +} + +static void +etherrtrace(Conn *c, Etherpkt *pkt, int len) +{ + Block *bp; + + bp = allocb(64); + memmove(bp->wp, pkt, len < 64 ? len : 64); + if(c->type != -2){ + u32int ms = nsec()/1000000LL; + bp->wp[58] = len>>8; + bp->wp[59] = len; + bp->wp[60] = ms>>24; + bp->wp[61] = ms>>16; + bp->wp[62] = ms>>8; + bp->wp[63] = ms; + } + bp->wp += 64; + cpass(c, bp); +} + +static Macent* +macent(uchar *ea) +{ + u32int h = (ea[0] | ea[1]<<8 | ea[2]<<16 | ea[3]<<24) ^ (ea[4] | ea[5]<<8); + return &mactab[h % nelem(mactab)]; +} + +static Block* +ethermux(Block *bp, Conn *from) +{ + Etherpkt *pkt; + Conn *c, *x; + int len, multi, tome, port, type, dispose; + + len = BLEN(bp); + if(len < ETHERHDRSIZE) + goto Drop; + pkt = (Etherpkt*)bp->rp; + if(!(multi = pkt->d[0] & 1)){ + tome = memcmp(pkt->d, macaddr, Eaddrlen) == 0; + if(!tome && from != nil && nprom == 0) + return bp; + } else { + tome = 0; + if(from == nil && nprom == 0 + && memcmp(pkt->d, bcast, Eaddrlen) != 0 + && activemulti(pkt->d) < 0) + goto Drop; + } + + port = -1; + if(nprom){ + if((from == nil || from->bridge) && (pkt->s[0] & 1) == 0){ + Macent *t = macent(pkt->s); + t->port = from == nil ? 0 : 1+(from - conn); + memmove(t->ea, pkt->s, Eaddrlen); + } + if(!tome && !multi){ + Macent *t = macent(pkt->d); + if(memcmp(t->ea, pkt->d, Eaddrlen) == 0) + port = t->port; + } + } + + x = nil; + type = (pkt->type[0]<<8)|pkt->type[1]; + dispose = tome || from == nil || port > 0; + + for(c = conn; c < &conn[nconn]; c++){ + if(!c->used) + continue; + if(c->type != type && c->type >= 0) + continue; + if(!tome && !multi && !c->prom) + continue; + if(c->bridge){ + if(tome || c == from) + continue; + if(port >= 0 && port != 1+(c - conn)) + continue; + } + if(c->headersonly || c->type == -2){ + etherrtrace(c, pkt, len); + continue; + } + if(dispose && x == nil) + x = c; + else + cpass(c, copyblock(bp, len)); + } + if(x != nil){ + cpass(x, bp); + return nil; + } + + if(dispose){ +Drop: freeb(bp); + return nil; + } + return bp; +} + +void +etheriq(Block *bp) +{ + stats.in++; + ethermux(bp, nil); +} + +static void +etheroq(Block *bp, Conn *from) +{ + if(!from->bridge) + memmove(((Etherpkt*)bp->rp)->s, macaddr, Eaddrlen); + bp = ethermux(bp, from); + if(bp == nil) + return; + stats.out++; + /* transmit frees buffer */ + bp->rp-=12; + memset(bp->rp, 0, 12); + write(grecon, bp->rp, BLEN(bp)); + freeb(bp); +} + +static void +grereadproc(void *) +{ + char err[ERRMAX]; + uchar buf[1600]; + int nerr; + int len; + Block *b; + ushort flags; + + atnotify(inote, 1); + + threadsetname("grereadproc"); + + nerr = 0; + for(;;){ + /* receive allocates buffer and calls etheriq(b, 1); */ + if((len = read(grecon, buf, 1600)) < 0){ + rerrstr(err, sizeof(err)); + if(strstr(err, "interrupted") || strstr(err, "timed out")) + continue; + fprint(2, "grereadproc: %s\n", err); + if(++nerr < 3) + continue; + threadexitsall(err); + } + nerr = 0; + + flags = nhgets(buf+8); + if(flags){ + stats.bogus++; + continue; + } + + b = allocb(1600); + memcpy(b->wp, buf+12, len-12); + b->wp+=(len-12); + etheriq(b); + } +} + +Srv fs = +{ +.attach= fsattach, +.destroyfid= fsdestroyfid, +.walk1= fswalk1, +.open= fsopen, +.read= fsread, +.write= fswrite, +.stat= fsstat, +.flush= fsflush, +}; + +static void +usage(void) +{ + fprint(2, "usage: %s [-dD] [-i index] [-a addr] remote\n", argv0); + exits("usage"); +} + +void +threadmain(int argc, char **argv) +{ + char s[64], *t, *d; + int idx = 0; + + fmtinstall('E', eipfmt); + + + ARGBEGIN { + case 'd': + debug = 1; + break; + case 'D': + chatty9p++; + break; + case 'i': + idx = atoi(EARGF(usage())); + case 'a': + setmac = 1; + if(parseether(macaddr, EARGF(usage())) != 0) + usage(); + break; + default: + usage(); + } ARGEND; + + if(argc != 1) + usage(); + + if(!setmac){ + genrandom(macaddr, Eaddrlen); + macaddr[0] &= 0xfe; + } + + d = smprint("gre!%s!25944", argv[0]); + grecon = dial(d, nil, nil, nil); + + if(grecon == -1) + sysfatal("%r"); + + werrstr(""); + + proccreate(grereadproc, nil, 8*1024); + + atnotify(inote, 1); + time0 = time(0); + + tab[Qiface].name = smprint("etherG%d", idx); + snprint(s, sizeof(s), "%d.ugre", idx); + threadpostmountsrv(&fs, s, "/net/", MAFTER); + + threadexits(0); +} + +Block* +allocb(int size) +{ + Block *b; + + b = emalloc9p(sizeof(*b) + size); + b->lim = b->base + size; + b->rp = b->base; + b->wp = b->base; + b->next = nil; + return b; +} + +Block* +copyblock(Block *b, int count) +{ + Block *nb; + + if(count > BLEN(b)) + count = BLEN(b); + nb = allocb(count); + memmove(nb->wp, b->rp, count); + nb->wp += count; + return nb; +} --- a/./sys/src/cmd/ip/mkfile +++ b/./sys/src/cmd/ip/mkfile @@ -4,6 +4,7 @@ ayiya\ dhcp6d\ dhcpclient\ + egre\ ftpd\ gping\ hogports\ ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [9front] ethernet over gre 2023-09-23 14:26 [9front] ethernet over gre Arne Meyer 2023-09-23 15:32 ` Jacob Moody @ 2023-09-23 19:50 ` Steve Simon 2023-09-23 20:41 ` Arne Meyer 1 sibling, 1 reply; 7+ messages in thread From: Steve Simon @ 2023-09-23 19:50 UTC (permalink / raw) To: 9front just a suggestion… you could refactor a bit to take the ip address in the dialstring, as implemented in telco(1). i am not sure how much more useful that would really be but it might be classed as a slightly more plan9-ey implementation. -Steve > On 23 Sep 2023, at 3:30 pm, Arne Meyer <meyer.arne83@netcologne.de> wrote: > > Hello, > > i finally found the time to polish up my implementation of ethernet over gre for 9front. > This is based on nusb/ether. It uses gre from the ip stack. I tested it with OpenBSD egre. > For now only ipv4 is supported for the outside of the tunnel. > > 9front: > ip address is 192.168.178.21 > > egre 192.168.178.20 > ip/ipconfig -m 1400 ether /net/etherG0 10.0.0.1 255.255.255.0 > > OpenBSD: > > ifconfig egre0 create > ifconfig egre0 tunnel 192.168.178.20 192.168.178.21 > ifconfig egre0 10.0.0.2/24 mtu 1400 > ifconfig egre0 up > > Greetings, > Arnefrom postmaster@9front: > The following attachment had content that we can't > prove to be harmless. To avoid possible automatic > execution, we changed the content headers. > The original header was: > > Content-Type: text/x-c; charset=UTF-8; name=egre.c > Content-Transfer-Encoding: base64 > Content-Disposition: attachment; filename=egre.c > <egre.c.suspect> ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [9front] ethernet over gre 2023-09-23 19:50 ` Steve Simon @ 2023-09-23 20:41 ` Arne Meyer 0 siblings, 0 replies; 7+ messages in thread From: Arne Meyer @ 2023-09-23 20:41 UTC (permalink / raw) To: 9front hey Steve, yes there is some refactoring to be done. the gre code in 9front is quite crufty and doesn't support ipv6 right now. It's next on my list. > Steve Simon <steve@quintile.net> hat am 23.09.2023 21:50 CEST geschrieben: > > > just a suggestion… > you could refactor a bit to take the ip address in the dialstring, as implemented in telco(1). > > i am not sure how much more useful that would really be but it might be classed as a slightly more plan9-ey implementation. > > -Steve > > > > > > On 23 Sep 2023, at 3:30 pm, Arne Meyer <meyer.arne83@netcologne.de> wrote: > > > > Hello, > > > > i finally found the time to polish up my implementation of ethernet over gre for 9front. > > This is based on nusb/ether. It uses gre from the ip stack. I tested it with OpenBSD egre. > > For now only ipv4 is supported for the outside of the tunnel. > > > > 9front: > > ip address is 192.168.178.21 > > > > egre 192.168.178.20 > > ip/ipconfig -m 1400 ether /net/etherG0 10.0.0.1 255.255.255.0 > > > > OpenBSD: > > > > ifconfig egre0 create > > ifconfig egre0 tunnel 192.168.178.20 192.168.178.21 > > ifconfig egre0 10.0.0.2/24 mtu 1400 > > ifconfig egre0 up > > > > Greetings, > > Arnefrom postmaster@9front: > > The following attachment had content that we can't > > prove to be harmless. To avoid possible automatic > > execution, we changed the content headers. > > The original header was: > > > > Content-Type: text/x-c; charset=UTF-8; name=egre.c > > Content-Transfer-Encoding: base64 > > Content-Disposition: attachment; filename=egre.c > > <egre.c.suspect> ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2023-09-23 20:43 UTC | newest] Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2023-09-23 14:26 [9front] ethernet over gre Arne Meyer 2023-09-23 15:32 ` Jacob Moody 2023-09-23 15:46 ` Arne Meyer 2023-09-23 15:56 ` Jacob Moody 2023-09-23 20:33 ` Arne Meyer 2023-09-23 19:50 ` Steve Simon 2023-09-23 20:41 ` Arne Meyer
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).