iproute.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "../port/error.h"
  7. #include "ip.h"
  8. static void walkadd(Fs*, Route**, Route*);
  9. static void addnode(Fs*, Route**, Route*);
  10. static void calcd(Route*);
  11. /* these are used for all instances of IP */
  12. Route* v4freelist;
  13. Route* v6freelist;
  14. RWlock routelock;
  15. ulong v4routegeneration, v6routegeneration;
  16. static void
  17. freeroute(Route *r)
  18. {
  19. Route **l;
  20. r->left = nil;
  21. r->right = nil;
  22. if(r->type & Rv4)
  23. l = &v4freelist;
  24. else
  25. l = &v6freelist;
  26. r->mid = *l;
  27. *l = r;
  28. }
  29. static Route*
  30. allocroute(int type)
  31. {
  32. Route *r;
  33. int n;
  34. Route **l;
  35. if(type & Rv4){
  36. n = sizeof(RouteTree) + sizeof(V4route);
  37. l = &v4freelist;
  38. } else {
  39. n = sizeof(RouteTree) + sizeof(V6route);
  40. l = &v6freelist;
  41. }
  42. r = *l;
  43. if(r != nil){
  44. *l = r->mid;
  45. } else {
  46. r = malloc(n);
  47. if(r == nil)
  48. panic("out of routing nodes");
  49. }
  50. memset(r, 0, n);
  51. r->type = type;
  52. r->ifc = nil;
  53. r->ref = 1;
  54. return r;
  55. }
  56. static void
  57. addqueue(Route **q, Route *r)
  58. {
  59. Route *l;
  60. if(r == nil)
  61. return;
  62. l = allocroute(r->type);
  63. l->mid = *q;
  64. *q = l;
  65. l->left = r;
  66. }
  67. /*
  68. * compare 2 v6 addresses
  69. */
  70. static int
  71. lcmp(ulong *a, ulong *b)
  72. {
  73. int i;
  74. for(i = 0; i < IPllen; i++){
  75. if(a[i] > b[i])
  76. return 1;
  77. if(a[i] < b[i])
  78. return -1;
  79. }
  80. return 0;
  81. }
  82. /*
  83. * compare 2 v4 or v6 ranges
  84. */
  85. enum
  86. {
  87. Rpreceeds,
  88. Rfollows,
  89. Requals,
  90. Rcontains,
  91. Rcontained,
  92. };
  93. static int
  94. rangecompare(Route *a, Route *b)
  95. {
  96. if(a->type & Rv4){
  97. if(a->v4.endaddress < b->v4.address)
  98. return Rpreceeds;
  99. if(a->v4.address > b->v4.endaddress)
  100. return Rfollows;
  101. if(a->v4.address <= b->v4.address
  102. && a->v4.endaddress >= b->v4.endaddress){
  103. if(a->v4.address == b->v4.address
  104. && a->v4.endaddress == b->v4.endaddress)
  105. return Requals;
  106. return Rcontains;
  107. }
  108. return Rcontained;
  109. }
  110. if(lcmp(a->v6.endaddress, b->v6.address) < 0)
  111. return Rpreceeds;
  112. if(lcmp(a->v6.address, b->v6.endaddress) > 0)
  113. return Rfollows;
  114. if(lcmp(a->v6.address, b->v6.address) <= 0
  115. && lcmp(a->v6.endaddress, b->v6.endaddress) >= 0){
  116. if(lcmp(a->v6.address, b->v6.address) == 0
  117. && lcmp(a->v6.endaddress, b->v6.endaddress) == 0)
  118. return Requals;
  119. return Rcontains;
  120. }
  121. return Rcontained;
  122. }
  123. static void
  124. copygate(Route *old, Route *new)
  125. {
  126. if(new->type & Rv4)
  127. memmove(old->v4.gate, new->v4.gate, IPv4addrlen);
  128. else
  129. memmove(old->v6.gate, new->v6.gate, IPaddrlen);
  130. }
  131. /*
  132. * walk down a tree adding nodes back in
  133. */
  134. static void
  135. walkadd(Fs *f, Route **root, Route *p)
  136. {
  137. Route *l, *r;
  138. l = p->left;
  139. r = p->right;
  140. p->left = 0;
  141. p->right = 0;
  142. addnode(f, root, p);
  143. if(l)
  144. walkadd(f, root, l);
  145. if(r)
  146. walkadd(f, root, r);
  147. }
  148. /*
  149. * calculate depth
  150. */
  151. static void
  152. calcd(Route *p)
  153. {
  154. Route *q;
  155. int d;
  156. if(p) {
  157. d = 0;
  158. q = p->left;
  159. if(q)
  160. d = q->depth;
  161. q = p->right;
  162. if(q && q->depth > d)
  163. d = q->depth;
  164. q = p->mid;
  165. if(q && q->depth > d)
  166. d = q->depth;
  167. p->depth = d+1;
  168. }
  169. }
  170. /*
  171. * balance the tree at the current node
  172. */
  173. static void
  174. balancetree(Route **cur)
  175. {
  176. Route *p, *l, *r;
  177. int dl, dr;
  178. /*
  179. * if left and right are
  180. * too out of balance,
  181. * rotate tree node
  182. */
  183. p = *cur;
  184. dl = 0; if(l = p->left) dl = l->depth;
  185. dr = 0; if(r = p->right) dr = r->depth;
  186. if(dl > dr+1) {
  187. p->left = l->right;
  188. l->right = p;
  189. *cur = l;
  190. calcd(p);
  191. calcd(l);
  192. } else
  193. if(dr > dl+1) {
  194. p->right = r->left;
  195. r->left = p;
  196. *cur = r;
  197. calcd(p);
  198. calcd(r);
  199. } else
  200. calcd(p);
  201. }
  202. /*
  203. * add a new node to the tree
  204. */
  205. static void
  206. addnode(Fs *f, Route **cur, Route *new)
  207. {
  208. Route *p;
  209. p = *cur;
  210. if(p == 0) {
  211. *cur = new;
  212. new->depth = 1;
  213. return;
  214. }
  215. switch(rangecompare(new, p)){
  216. case Rpreceeds:
  217. addnode(f, &p->left, new);
  218. break;
  219. case Rfollows:
  220. addnode(f, &p->right, new);
  221. break;
  222. case Rcontains:
  223. /*
  224. * if new node is superset
  225. * of tree node,
  226. * replace tree node and
  227. * queue tree node to be
  228. * merged into root.
  229. */
  230. *cur = new;
  231. new->depth = 1;
  232. addqueue(&f->queue, p);
  233. break;
  234. case Requals:
  235. /*
  236. * supercede the old entry if the old one isn't
  237. * a local interface.
  238. */
  239. if((p->type & Rifc) == 0){
  240. p->type = new->type;
  241. p->ifcid = -1;
  242. copygate(p, new);
  243. } else if(new->type & Rifc)
  244. p->ref++;
  245. freeroute(new);
  246. break;
  247. case Rcontained:
  248. addnode(f, &p->mid, new);
  249. break;
  250. }
  251. balancetree(cur);
  252. }
  253. #define V4H(a) ((a&0x07ffffff)>>(32-Lroot-5))
  254. void
  255. v4addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
  256. {
  257. Route *p;
  258. ulong sa;
  259. ulong m;
  260. ulong ea;
  261. int h, eh;
  262. m = nhgetl(mask);
  263. sa = nhgetl(a) & m;
  264. ea = sa | ~m;
  265. eh = V4H(ea);
  266. for(h=V4H(sa); h<=eh; h++) {
  267. p = allocroute(Rv4 | type);
  268. p->v4.address = sa;
  269. p->v4.endaddress = ea;
  270. memmove(p->v4.gate, gate, sizeof(p->v4.gate));
  271. memmove(p->tag, tag, sizeof(p->tag));
  272. wlock(&routelock);
  273. addnode(f, &f->v4root[h], p);
  274. while(p = f->queue) {
  275. f->queue = p->mid;
  276. walkadd(f, &f->v4root[h], p->left);
  277. freeroute(p);
  278. }
  279. wunlock(&routelock);
  280. }
  281. v4routegeneration++;
  282. ipifcaddroute(f, Rv4, a, mask, gate, type);
  283. }
  284. #define V6H(a) (((a)[IPllen-1] & 0x07ffffff)>>(32-Lroot-5))
  285. #define ISDFLT(a, mask, tag) ((ipcmp((a),v6Unspecified)==0) && (ipcmp((mask),v6Unspecified)==0) && (strcmp((tag), "ra")!=0))
  286. void
  287. v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
  288. {
  289. Route *p;
  290. ulong sa[IPllen], ea[IPllen];
  291. ulong x, y;
  292. int h, eh;
  293. /*
  294. if(ISDFLT(a, mask, tag))
  295. f->v6p->cdrouter = -1;
  296. */
  297. for(h = 0; h < IPllen; h++){
  298. x = nhgetl(a+4*h);
  299. y = nhgetl(mask+4*h);
  300. sa[h] = x & y;
  301. ea[h] = x | ~y;
  302. }
  303. eh = V6H(ea);
  304. for(h = V6H(sa); h <= eh; h++) {
  305. p = allocroute(type);
  306. memmove(p->v6.address, sa, IPaddrlen);
  307. memmove(p->v6.endaddress, ea, IPaddrlen);
  308. memmove(p->v6.gate, gate, IPaddrlen);
  309. memmove(p->tag, tag, sizeof(p->tag));
  310. wlock(&routelock);
  311. addnode(f, &f->v6root[h], p);
  312. while(p = f->queue) {
  313. f->queue = p->mid;
  314. walkadd(f, &f->v6root[h], p->left);
  315. freeroute(p);
  316. }
  317. wunlock(&routelock);
  318. }
  319. v6routegeneration++;
  320. ipifcaddroute(f, 0, a, mask, gate, type);
  321. }
  322. Route**
  323. looknode(Route **cur, Route *r)
  324. {
  325. Route *p;
  326. for(;;){
  327. p = *cur;
  328. if(p == 0)
  329. return 0;
  330. switch(rangecompare(r, p)){
  331. case Rcontains:
  332. return 0;
  333. case Rpreceeds:
  334. cur = &p->left;
  335. break;
  336. case Rfollows:
  337. cur = &p->right;
  338. break;
  339. case Rcontained:
  340. cur = &p->mid;
  341. break;
  342. case Requals:
  343. return cur;
  344. }
  345. }
  346. }
  347. void
  348. v4delroute(Fs *f, uchar *a, uchar *mask, int dolock)
  349. {
  350. Route **r, *p;
  351. Route rt;
  352. int h, eh;
  353. ulong m;
  354. m = nhgetl(mask);
  355. rt.v4.address = nhgetl(a) & m;
  356. rt.v4.endaddress = rt.v4.address | ~m;
  357. rt.type = Rv4;
  358. eh = V4H(rt.v4.endaddress);
  359. for(h=V4H(rt.v4.address); h<=eh; h++) {
  360. if(dolock)
  361. wlock(&routelock);
  362. r = looknode(&f->v4root[h], &rt);
  363. if(r) {
  364. p = *r;
  365. if(--(p->ref) == 0){
  366. *r = 0;
  367. addqueue(&f->queue, p->left);
  368. addqueue(&f->queue, p->mid);
  369. addqueue(&f->queue, p->right);
  370. freeroute(p);
  371. while(p = f->queue) {
  372. f->queue = p->mid;
  373. walkadd(f, &f->v4root[h], p->left);
  374. freeroute(p);
  375. }
  376. }
  377. }
  378. if(dolock)
  379. wunlock(&routelock);
  380. }
  381. v4routegeneration++;
  382. ipifcremroute(f, Rv4, a, mask);
  383. }
  384. void
  385. v6delroute(Fs *f, uchar *a, uchar *mask, int dolock)
  386. {
  387. Route **r, *p;
  388. Route rt;
  389. int h, eh;
  390. ulong x, y;
  391. for(h = 0; h < IPllen; h++){
  392. x = nhgetl(a+4*h);
  393. y = nhgetl(mask+4*h);
  394. rt.v6.address[h] = x & y;
  395. rt.v6.endaddress[h] = x | ~y;
  396. }
  397. rt.type = 0;
  398. eh = V6H(rt.v6.endaddress);
  399. for(h=V6H(rt.v6.address); h<=eh; h++) {
  400. if(dolock)
  401. wlock(&routelock);
  402. r = looknode(&f->v6root[h], &rt);
  403. if(r) {
  404. p = *r;
  405. if(--(p->ref) == 0){
  406. *r = 0;
  407. addqueue(&f->queue, p->left);
  408. addqueue(&f->queue, p->mid);
  409. addqueue(&f->queue, p->right);
  410. freeroute(p);
  411. while(p = f->queue) {
  412. f->queue = p->mid;
  413. walkadd(f, &f->v6root[h], p->left);
  414. freeroute(p);
  415. }
  416. }
  417. }
  418. if(dolock)
  419. wunlock(&routelock);
  420. }
  421. v6routegeneration++;
  422. ipifcremroute(f, 0, a, mask);
  423. }
  424. Route*
  425. v4lookup(Fs *f, uchar *a, Conv *c)
  426. {
  427. Route *p, *q;
  428. ulong la;
  429. uchar gate[IPaddrlen];
  430. Ipifc *ifc;
  431. if(c != nil && c->r != nil && c->r->ifc != nil && c->rgen == v4routegeneration)
  432. return c->r;
  433. la = nhgetl(a);
  434. q = nil;
  435. for(p=f->v4root[V4H(la)]; p;)
  436. if(la >= p->v4.address) {
  437. if(la <= p->v4.endaddress) {
  438. q = p;
  439. p = p->mid;
  440. } else
  441. p = p->right;
  442. } else
  443. p = p->left;
  444. if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
  445. if(q->type & Rifc) {
  446. hnputl(gate+IPv4off, q->v4.address);
  447. memmove(gate, v4prefix, IPv4off);
  448. } else
  449. v4tov6(gate, q->v4.gate);
  450. ifc = findipifc(f, gate, q->type);
  451. if(ifc == nil)
  452. return nil;
  453. q->ifc = ifc;
  454. q->ifcid = ifc->ifcid;
  455. }
  456. if(c != nil){
  457. c->r = q;
  458. c->rgen = v4routegeneration;
  459. }
  460. return q;
  461. }
  462. Route*
  463. v6lookup(Fs *f, uchar *a, Conv *c)
  464. {
  465. Route *p, *q;
  466. ulong la[IPllen];
  467. int h;
  468. ulong x, y;
  469. uchar gate[IPaddrlen];
  470. Ipifc *ifc;
  471. if(memcmp(a, v4prefix, IPv4off) == 0){
  472. q = v4lookup(f, a+IPv4off, c);
  473. if(q != nil)
  474. return q;
  475. }
  476. if(c != nil && c->r != nil && c->r->ifc != nil && c->rgen == v6routegeneration)
  477. return c->r;
  478. for(h = 0; h < IPllen; h++)
  479. la[h] = nhgetl(a+4*h);
  480. q = 0;
  481. for(p=f->v6root[V6H(la)]; p;){
  482. for(h = 0; h < IPllen; h++){
  483. x = la[h];
  484. y = p->v6.address[h];
  485. if(x == y)
  486. continue;
  487. if(x < y){
  488. p = p->left;
  489. goto next;
  490. }
  491. break;
  492. }
  493. for(h = 0; h < IPllen; h++){
  494. x = la[h];
  495. y = p->v6.endaddress[h];
  496. if(x == y)
  497. continue;
  498. if(x > y){
  499. p = p->right;
  500. goto next;
  501. }
  502. break;
  503. }
  504. q = p;
  505. p = p->mid;
  506. next: ;
  507. }
  508. if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
  509. if(q->type & Rifc) {
  510. for(h = 0; h < IPllen; h++)
  511. hnputl(gate+4*h, q->v6.address[h]);
  512. ifc = findipifc(f, gate, q->type);
  513. } else
  514. ifc = findipifc(f, q->v6.gate, q->type);
  515. if(ifc == nil)
  516. return nil;
  517. q->ifc = ifc;
  518. q->ifcid = ifc->ifcid;
  519. }
  520. if(c != nil){
  521. c->r = q;
  522. c->rgen = v6routegeneration;
  523. }
  524. return q;
  525. }
  526. void
  527. routetype(int type, char *p)
  528. {
  529. memset(p, ' ', 4);
  530. p[4] = 0;
  531. if(type & Rv4)
  532. *p++ = '4';
  533. else
  534. *p++ = '6';
  535. if(type & Rifc)
  536. *p++ = 'i';
  537. if(type & Runi)
  538. *p++ = 'u';
  539. else if(type & Rbcast)
  540. *p++ = 'b';
  541. else if(type & Rmulti)
  542. *p++ = 'm';
  543. if(type & Rptpt)
  544. *p = 'p';
  545. }
  546. char *rformat = "%-15I %-4M %-15I %4.4s %4.4s %3s\n";
  547. void
  548. convroute(Route *r, uchar *addr, uchar *mask, uchar *gate, char *t, int *nifc)
  549. {
  550. int i;
  551. if(r->type & Rv4){
  552. memmove(addr, v4prefix, IPv4off);
  553. hnputl(addr+IPv4off, r->v4.address);
  554. memset(mask, 0xff, IPv4off);
  555. hnputl(mask+IPv4off, ~(r->v4.endaddress ^ r->v4.address));
  556. memmove(gate, v4prefix, IPv4off);
  557. memmove(gate+IPv4off, r->v4.gate, IPv4addrlen);
  558. } else {
  559. for(i = 0; i < IPllen; i++){
  560. hnputl(addr + 4*i, r->v6.address[i]);
  561. hnputl(mask + 4*i, ~(r->v6.endaddress[i] ^ r->v6.address[i]));
  562. }
  563. memmove(gate, r->v6.gate, IPaddrlen);
  564. }
  565. routetype(r->type, t);
  566. if(r->ifc)
  567. *nifc = r->ifc->conv->x;
  568. else
  569. *nifc = -1;
  570. }
  571. /*
  572. * this code is not in rr to reduce stack size
  573. */
  574. static void
  575. sprintroute(Route *r, Routewalk *rw)
  576. {
  577. int nifc, n;
  578. char t[5], *iname, ifbuf[5];
  579. uchar addr[IPaddrlen], mask[IPaddrlen], gate[IPaddrlen];
  580. char *p;
  581. convroute(r, addr, mask, gate, t, &nifc);
  582. iname = "-";
  583. if(nifc != -1) {
  584. iname = ifbuf;
  585. snprint(ifbuf, sizeof ifbuf, "%d", nifc);
  586. }
  587. p = seprint(rw->p, rw->e, rformat, addr, mask, gate, t, r->tag, iname);
  588. if(rw->o < 0){
  589. n = p - rw->p;
  590. if(n > -rw->o){
  591. memmove(rw->p, rw->p-rw->o, n+rw->o);
  592. rw->p = p + rw->o;
  593. }
  594. rw->o += n;
  595. } else
  596. rw->p = p;
  597. }
  598. /*
  599. * recurse descending tree, applying the function in Routewalk
  600. */
  601. static int
  602. rr(Route *r, Routewalk *rw)
  603. {
  604. int h;
  605. if(rw->e <= rw->p)
  606. return 0;
  607. if(r == nil)
  608. return 1;
  609. if(rr(r->left, rw) == 0)
  610. return 0;
  611. if(r->type & Rv4)
  612. h = V4H(r->v4.address);
  613. else
  614. h = V6H(r->v6.address);
  615. if(h == rw->h)
  616. rw->walk(r, rw);
  617. if(rr(r->mid, rw) == 0)
  618. return 0;
  619. return rr(r->right, rw);
  620. }
  621. void
  622. ipwalkroutes(Fs *f, Routewalk *rw)
  623. {
  624. rlock(&routelock);
  625. if(rw->e > rw->p) {
  626. for(rw->h = 0; rw->h < nelem(f->v4root); rw->h++)
  627. if(rr(f->v4root[rw->h], rw) == 0)
  628. break;
  629. }
  630. if(rw->e > rw->p) {
  631. for(rw->h = 0; rw->h < nelem(f->v6root); rw->h++)
  632. if(rr(f->v6root[rw->h], rw) == 0)
  633. break;
  634. }
  635. runlock(&routelock);
  636. }
  637. long
  638. routeread(Fs *f, char *p, ulong offset, int n)
  639. {
  640. Routewalk rw;
  641. rw.p = p;
  642. rw.e = p+n;
  643. rw.o = -offset;
  644. rw.walk = sprintroute;
  645. ipwalkroutes(f, &rw);
  646. return rw.p - p;
  647. }
  648. /*
  649. * this code is not in routeflush to reduce stack size
  650. */
  651. void
  652. delroute(Fs *f, Route *r, int dolock)
  653. {
  654. uchar addr[IPaddrlen];
  655. uchar mask[IPaddrlen];
  656. uchar gate[IPaddrlen];
  657. char t[5];
  658. int nifc;
  659. convroute(r, addr, mask, gate, t, &nifc);
  660. if(r->type & Rv4)
  661. v4delroute(f, addr+IPv4off, mask+IPv4off, dolock);
  662. else
  663. v6delroute(f, addr, mask, dolock);
  664. }
  665. /*
  666. * recurse until one route is deleted
  667. * returns 0 if nothing is deleted, 1 otherwise
  668. */
  669. int
  670. routeflush(Fs *f, Route *r, char *tag)
  671. {
  672. if(r == nil)
  673. return 0;
  674. if(routeflush(f, r->mid, tag))
  675. return 1;
  676. if(routeflush(f, r->left, tag))
  677. return 1;
  678. if(routeflush(f, r->right, tag))
  679. return 1;
  680. if((r->type & Rifc) == 0){
  681. if(tag == nil || strncmp(tag, r->tag, sizeof(r->tag)) == 0){
  682. delroute(f, r, 0);
  683. return 1;
  684. }
  685. }
  686. return 0;
  687. }
  688. long
  689. routewrite(Fs *f, Chan *c, char *p, int n)
  690. {
  691. int h, changed;
  692. char *tag;
  693. Cmdbuf *cb;
  694. uchar addr[IPaddrlen];
  695. uchar mask[IPaddrlen];
  696. uchar gate[IPaddrlen];
  697. IPaux *a, *na;
  698. cb = parsecmd(p, n);
  699. if(waserror()){
  700. free(cb);
  701. nexterror();
  702. }
  703. if(strcmp(cb->f[0], "flush") == 0){
  704. tag = cb->f[1];
  705. for(h = 0; h < nelem(f->v4root); h++)
  706. for(changed = 1; changed;){
  707. wlock(&routelock);
  708. changed = routeflush(f, f->v4root[h], tag);
  709. wunlock(&routelock);
  710. }
  711. for(h = 0; h < nelem(f->v6root); h++)
  712. for(changed = 1; changed;){
  713. wlock(&routelock);
  714. changed = routeflush(f, f->v6root[h], tag);
  715. wunlock(&routelock);
  716. }
  717. } else if(strcmp(cb->f[0], "remove") == 0){
  718. if(cb->nf < 3)
  719. error(Ebadarg);
  720. parseip(addr, cb->f[1]);
  721. parseipmask(mask, cb->f[2]);
  722. if(memcmp(addr, v4prefix, IPv4off) == 0)
  723. v4delroute(f, addr+IPv4off, mask+IPv4off, 1);
  724. else
  725. v6delroute(f, addr, mask, 1);
  726. } else if(strcmp(cb->f[0], "add") == 0){
  727. if(cb->nf < 4)
  728. error(Ebadarg);
  729. parseip(addr, cb->f[1]);
  730. parseipmask(mask, cb->f[2]);
  731. parseip(gate, cb->f[3]);
  732. tag = "none";
  733. if(c != nil){
  734. a = c->aux;
  735. tag = a->tag;
  736. }
  737. if(memcmp(addr, v4prefix, IPv4off) == 0)
  738. v4addroute(f, tag, addr+IPv4off, mask+IPv4off, gate+IPv4off, 0);
  739. else
  740. v6addroute(f, tag, addr, mask, gate, 0);
  741. } else if(strcmp(cb->f[0], "tag") == 0) {
  742. if(cb->nf < 2)
  743. error(Ebadarg);
  744. a = c->aux;
  745. na = newipaux(a->owner, cb->f[1]);
  746. c->aux = na;
  747. free(a);
  748. }
  749. poperror();
  750. free(cb);
  751. return n;
  752. }