2 #include "../port/lib.h"
6 #include "../port/error.h"
10 static void walkadd(Fs*, Route**, Route*);
11 static void addnode(Fs*, Route**, Route*);
12 static void calcd(Route*);
14 /* these are used for all instances of IP */
15 static Route* v4freelist;
16 static Route* v6freelist;
17 static RWlock routelock;
18 static ulong v4routegeneration, v6routegeneration;
43 n = sizeof(RouteTree) + sizeof(V4route);
46 n = sizeof(RouteTree) + sizeof(V6route);
56 panic("out of routing nodes");
67 addqueue(Route **q, Route *r)
74 l = allocroute(r->type);
81 * compare 2 v6 addresses
84 lcmp(ulong *a, ulong *b)
88 for(i = 0; i < IPllen; i++){
98 * compare 2 v4 or v6 ranges
110 rangecompare(Route *a, Route *b)
113 if(a->v4.endaddress < b->v4.address)
116 if(a->v4.address > b->v4.endaddress)
119 if(a->v4.address <= b->v4.address
120 && a->v4.endaddress >= b->v4.endaddress){
121 if(a->v4.address == b->v4.address
122 && a->v4.endaddress == b->v4.endaddress)
129 if(lcmp(a->v6.endaddress, b->v6.address) < 0)
132 if(lcmp(a->v6.address, b->v6.endaddress) > 0)
135 if(lcmp(a->v6.address, b->v6.address) <= 0
136 && lcmp(a->v6.endaddress, b->v6.endaddress) >= 0){
137 if(lcmp(a->v6.address, b->v6.address) == 0
138 && lcmp(a->v6.endaddress, b->v6.endaddress) == 0)
147 copygate(Route *old, Route *new)
150 memmove(old->v4.gate, new->v4.gate, IPv4addrlen);
152 memmove(old->v6.gate, new->v6.gate, IPaddrlen);
156 * walk down a tree adding nodes back in
159 walkadd(Fs *f, Route **root, Route *p)
189 if(q && q->depth > d)
192 if(q && q->depth > d)
199 * balance the tree at the current node
202 balancetree(Route **cur)
208 * if left and right are
209 * too out of balance,
213 dl = 0; if(l = p->left) dl = l->depth;
214 dr = 0; if(r = p->right) dr = r->depth;
234 * add a new node to the tree
237 addnode(Fs *f, Route **cur, Route *new)
248 switch(rangecompare(new, p)){
250 addnode(f, &p->left, new);
253 addnode(f, &p->right, new);
257 * if new node is superset
259 * replace tree node and
260 * queue tree node to be
265 addqueue(&f->queue, p);
269 * supercede the old entry if the old one isn't
272 if((p->type & Rifc) == 0){
276 } else if(new->type & Rifc)
281 addnode(f, &p->mid, new);
288 #define V4H(a) ((a&0x07ffffff)>>(32-Lroot-5))
291 v4addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
304 for(h=V4H(sa); h<=eh; h++) {
305 p = allocroute(Rv4 | type);
307 p->v4.endaddress = ea;
308 memmove(p->v4.gate, gate, sizeof(p->v4.gate));
309 memmove(p->tag, tag, sizeof(p->tag));
312 addnode(f, &f->v4root[h], p);
313 while(p = f->queue) {
315 walkadd(f, &f->v4root[h], p->left);
322 ipifcaddroute(f, Rv4, a, mask, gate, type);
325 #define V6H(a) (((a)[IPllen-1] & 0x07ffffff)>>(32-Lroot-5))
326 #define ISDFLT(a, mask, tag) ((ipcmp((a),v6Unspecified)==0) && (ipcmp((mask),v6Unspecified)==0) && (strcmp((tag), "ra")!=0))
329 v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
332 ulong sa[IPllen], ea[IPllen];
337 if(ISDFLT(a, mask, tag))
338 f->v6p->cdrouter = -1;
342 for(h = 0; h < IPllen; h++){
344 y = nhgetl(mask+4*h);
350 for(h = V6H(sa); h <= eh; h++) {
351 p = allocroute(type);
352 memmove(p->v6.address, sa, IPaddrlen);
353 memmove(p->v6.endaddress, ea, IPaddrlen);
354 memmove(p->v6.gate, gate, IPaddrlen);
355 memmove(p->tag, tag, sizeof(p->tag));
358 addnode(f, &f->v6root[h], p);
359 while(p = f->queue) {
361 walkadd(f, &f->v6root[h], p->left);
368 ipifcaddroute(f, 0, a, mask, gate, type);
372 looknode(Route **cur, Route *r)
381 switch(rangecompare(r, p)){
400 v4delroute(Fs *f, uchar *a, uchar *mask, int dolock)
408 rt.v4.address = nhgetl(a) & m;
409 rt.v4.endaddress = rt.v4.address | ~m;
412 eh = V4H(rt.v4.endaddress);
413 for(h=V4H(rt.v4.address); h<=eh; h++) {
416 r = looknode(&f->v4root[h], &rt);
421 addqueue(&f->queue, p->left);
422 addqueue(&f->queue, p->mid);
423 addqueue(&f->queue, p->right);
425 while(p = f->queue) {
427 walkadd(f, &f->v4root[h], p->left);
437 ipifcremroute(f, Rv4, a, mask);
441 v6delroute(Fs *f, uchar *a, uchar *mask, int dolock)
448 for(h = 0; h < IPllen; h++){
450 y = nhgetl(mask+4*h);
451 rt.v6.address[h] = x & y;
452 rt.v6.endaddress[h] = x | ~y;
456 eh = V6H(rt.v6.endaddress);
457 for(h=V6H(rt.v6.address); h<=eh; h++) {
460 r = looknode(&f->v6root[h], &rt);
465 addqueue(&f->queue, p->left);
466 addqueue(&f->queue, p->mid);
467 addqueue(&f->queue, p->right);
469 while(p = f->queue) {
471 walkadd(f, &f->v6root[h], p->left);
481 ipifcremroute(f, 0, a, mask);
485 v4lookup(Fs *f, uchar *a, Conv *c)
489 uchar gate[IPaddrlen];
492 if(c != nil && c->r != nil && c->r->ifc != nil && c->rgen == v4routegeneration)
497 for(p=f->v4root[V4H(la)]; p;)
498 if(la >= p->v4.address) {
499 if(la <= p->v4.endaddress) {
507 if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
509 hnputl(gate+IPv4off, q->v4.address);
510 memmove(gate, v4prefix, IPv4off);
512 v4tov6(gate, q->v4.gate);
513 ifc = findipifc(f, gate, q->type);
517 q->ifcid = ifc->ifcid;
522 c->rgen = v4routegeneration;
529 v6lookup(Fs *f, uchar *a, Conv *c)
535 uchar gate[IPaddrlen];
538 if(memcmp(a, v4prefix, IPv4off) == 0){
539 q = v4lookup(f, a+IPv4off, c);
544 if(c != nil && c->r != nil && c->r->ifc != nil && c->rgen == v6routegeneration)
547 for(h = 0; h < IPllen; h++)
548 la[h] = nhgetl(a+4*h);
551 for(p=f->v6root[V6H(la)]; p;){
552 for(h = 0; h < IPllen; h++){
554 y = p->v6.address[h];
563 for(h = 0; h < IPllen; h++){
565 y = p->v6.endaddress[h];
579 if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
581 for(h = 0; h < IPllen; h++)
582 hnputl(gate+4*h, q->v6.address[h]);
583 ifc = findipifc(f, gate, q->type);
585 ifc = findipifc(f, q->v6.gate, q->type);
589 q->ifcid = ifc->ifcid;
593 c->rgen = v6routegeneration;
600 routetype(int type, char *p)
612 else if(type & Rbcast)
614 else if(type & Rmulti)
620 static char *rformat = "%-15I %-4M %-15I %4.4s %4.4s %3s\n";
623 convroute(Route *r, uchar *addr, uchar *mask, uchar *gate, char *t, int *nifc)
628 memmove(addr, v4prefix, IPv4off);
629 hnputl(addr+IPv4off, r->v4.address);
630 memset(mask, 0xff, IPv4off);
631 hnputl(mask+IPv4off, ~(r->v4.endaddress ^ r->v4.address));
632 memmove(gate, v4prefix, IPv4off);
633 memmove(gate+IPv4off, r->v4.gate, IPv4addrlen);
635 for(i = 0; i < IPllen; i++){
636 hnputl(addr + 4*i, r->v6.address[i]);
637 hnputl(mask + 4*i, ~(r->v6.endaddress[i] ^ r->v6.address[i]));
639 memmove(gate, r->v6.gate, IPaddrlen);
642 routetype(r->type, t);
645 *nifc = r->ifc->conv->x;
651 * this code is not in rr to reduce stack size
654 sprintroute(Route *r, Routewalk *rw)
657 char t[5], *iname, ifbuf[5];
658 uchar addr[IPaddrlen], mask[IPaddrlen], gate[IPaddrlen];
661 convroute(r, addr, mask, gate, t, &nifc);
665 snprint(ifbuf, sizeof ifbuf, "%d", nifc);
667 p = seprint(rw->p, rw->e, rformat, addr, mask, gate, t, r->tag, iname);
671 memmove(rw->p, rw->p-rw->o, n+rw->o);
680 * recurse descending tree, applying the function in Routewalk
683 rr(Route *r, Routewalk *rw)
692 if(rr(r->left, rw) == 0)
696 h = V4H(r->v4.address);
698 h = V6H(r->v6.address);
703 if(rr(r->mid, rw) == 0)
706 return rr(r->right, rw);
710 ipwalkroutes(Fs *f, Routewalk *rw)
714 for(rw->h = 0; rw->h < nelem(f->v4root); rw->h++)
715 if(rr(f->v4root[rw->h], rw) == 0)
719 for(rw->h = 0; rw->h < nelem(f->v6root); rw->h++)
720 if(rr(f->v6root[rw->h], rw) == 0)
727 routeread(Fs *f, char *p, ulong offset, int n)
734 rw.walk = sprintroute;
736 ipwalkroutes(f, &rw);
742 * this code is not in routeflush to reduce stack size
745 delroute(Fs *f, Route *r, int dolock)
747 uchar addr[IPaddrlen];
748 uchar mask[IPaddrlen];
749 uchar gate[IPaddrlen];
753 convroute(r, addr, mask, gate, t, &nifc);
755 v4delroute(f, addr+IPv4off, mask+IPv4off, dolock);
757 v6delroute(f, addr, mask, dolock);
761 * recurse until one route is deleted
762 * returns 0 if nothing is deleted, 1 otherwise
765 routeflush(Fs *f, Route *r, char *tag)
769 if(routeflush(f, r->mid, tag))
771 if(routeflush(f, r->left, tag))
773 if(routeflush(f, r->right, tag))
775 if((r->type & Rifc) == 0){
776 if(tag == nil || strncmp(tag, r->tag, sizeof(r->tag)) == 0){
785 routewrite(Fs *f, Chan *c, char *p, int n)
790 uchar addr[IPaddrlen];
791 uchar mask[IPaddrlen];
792 uchar gate[IPaddrlen];
801 error("short control request");
802 if(strcmp(cb->f[0], "flush") == 0){
804 for(h = 0; h < nelem(f->v4root); h++)
805 for(changed = 1; changed;){
807 changed = routeflush(f, f->v4root[h], tag);
810 for(h = 0; h < nelem(f->v6root); h++)
811 for(changed = 1; changed;){
813 changed = routeflush(f, f->v6root[h], tag);
816 } else if(strcmp(cb->f[0], "remove") == 0){
819 if (parseip(addr, cb->f[1]) == -1)
821 parseipmask(mask, cb->f[2]);
822 if(memcmp(addr, v4prefix, IPv4off) == 0)
823 v4delroute(f, addr+IPv4off, mask+IPv4off, 1);
825 v6delroute(f, addr, mask, 1);
826 } else if(strcmp(cb->f[0], "add") == 0){
829 if(parseip(addr, cb->f[1]) == -1 ||
830 parseip(gate, cb->f[3]) == -1)
832 parseipmask(mask, cb->f[2]);
838 if(memcmp(addr, v4prefix, IPv4off) == 0)
839 v4addroute(f, tag, addr+IPv4off, mask+IPv4off, gate+IPv4off, 0);
841 v6addroute(f, tag, addr, mask, gate, 0);
842 } else if(strcmp(cb->f[0], "tag") == 0) {
847 na = newipaux(a->owner, cb->f[1]);