devloopback.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743
  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. typedef struct Link Link;
  8. typedef struct Loop Loop;
  9. struct Link
  10. {
  11. Lock;
  12. int ref;
  13. long packets; /* total number of packets sent */
  14. long bytes; /* total number of bytes sent */
  15. int indrop; /* enable dropping on iq overflow */
  16. long soverflows; /* packets dropped because iq overflowed */
  17. long droprate; /* drop 1/droprate packets in tq */
  18. long drops; /* packets deliberately dropped */
  19. vlong delay0ns; /* nanosec of delay in the link */
  20. long delaynns; /* nanosec of delay per byte */
  21. Block *tq; /* transmission queue */
  22. Block *tqtail;
  23. vlong tout; /* time the last packet in tq is really out */
  24. vlong tin; /* time the head packet in tq enters the remote side */
  25. long limit; /* queue buffering limit */
  26. Queue *oq; /* output queue from other side & packets in the link */
  27. Queue *iq;
  28. Timer ci; /* time to move packets from next packet from oq */
  29. };
  30. struct Loop
  31. {
  32. QLock;
  33. int ref;
  34. int minmtu; /* smallest block transmittable */
  35. Loop *next;
  36. ulong path;
  37. Link link[2];
  38. };
  39. static struct
  40. {
  41. Lock;
  42. ulong path;
  43. } loopbackalloc;
  44. enum
  45. {
  46. Qtopdir= 1, /* top level directory */
  47. Qloopdir, /* loopback* directory */
  48. Qportdir, /* directory each end of the loop */
  49. Qctl,
  50. Qstatus,
  51. Qstats,
  52. Qdata,
  53. MaxQ,
  54. Nloopbacks = 5,
  55. Statelen = 23*1024, /* status buffer size */
  56. Tmsize = 8,
  57. Delayn = 10000, /* default delays in ns */
  58. Delay0 = 2500000,
  59. Loopqlim = 32*1024, /* default size of queues */
  60. };
  61. static Dirtab loopportdir[] =
  62. {
  63. "ctl", {Qctl}, 0, 0222,
  64. "status", {Qstatus}, 0, 0444,
  65. "stats", {Qstats}, 0, 0444,
  66. "data", {Qdata}, 0, 0666,
  67. };
  68. static Dirtab loopdirs[MaxQ];
  69. static Loop loopbacks[Nloopbacks];
  70. #define TYPE(x) (((ulong)(x))&0xff)
  71. #define ID(x) (((ulong)(x))>>8)
  72. #define QID(x,y) ((((ulong)(x))<<8)|((ulong)(y)))
  73. static void looper(Loop *lb);
  74. static long loopoput(Loop *lb, Link *link, Block *bp);
  75. static void ptime(uchar *p, vlong t);
  76. static vlong gtime(uchar *p);
  77. static void closelink(Link *link, int dofree);
  78. static void pushlink(Link *link, vlong now);
  79. static void freelb(Loop *lb);
  80. static void linkintr(Ureg*, Timer *ci);
  81. static void
  82. loopbackinit(void)
  83. {
  84. int i;
  85. for(i = 0; i < Nloopbacks; i++)
  86. loopbacks[i].path = i;
  87. /* invert directory tables for non-directory entries */
  88. for(i=0; i<nelem(loopportdir); i++)
  89. loopdirs[loopportdir[i].qid.path] = loopportdir[i];
  90. }
  91. static Chan*
  92. loopbackattach(char *spec)
  93. {
  94. Loop *volatile lb;
  95. Queue *q;
  96. Chan *c;
  97. int chan;
  98. int dev;
  99. dev = 0;
  100. if(spec != nil){
  101. dev = atoi(spec);
  102. if(dev >= Nloopbacks)
  103. error(Ebadspec);
  104. }
  105. c = devattach('X', spec);
  106. lb = &loopbacks[dev];
  107. qlock(lb);
  108. if(waserror()){
  109. lb->ref--;
  110. qunlock(lb);
  111. nexterror();
  112. }
  113. lb->ref++;
  114. if(lb->ref == 1){
  115. for(chan = 0; chan < 2; chan++){
  116. lb->link[chan].ci.mode = Trelative;
  117. lb->link[chan].ci.a = &lb->link[chan];
  118. lb->link[chan].ci.f = linkintr;
  119. lb->link[chan].limit = Loopqlim;
  120. q = qopen(lb->link[chan].limit, 0, 0, 0);
  121. lb->link[chan].iq = q;
  122. if(q == nil){
  123. freelb(lb);
  124. exhausted("memory");
  125. }
  126. q = qopen(lb->link[chan].limit, 0, 0, 0);
  127. lb->link[chan].oq = q;
  128. if(q == nil){
  129. freelb(lb);
  130. exhausted("memory");
  131. }
  132. lb->link[chan].indrop = 1;
  133. lb->link[chan].delaynns = Delayn;
  134. lb->link[chan].delay0ns = Delay0;
  135. }
  136. }
  137. poperror();
  138. qunlock(lb);
  139. mkqid(&c->qid, QID(0, Qtopdir), 0, QTDIR);
  140. c->aux = lb;
  141. c->dev = dev;
  142. return c;
  143. }
  144. static int
  145. loopbackgen(Chan *c, char*, Dirtab*, int, int i, Dir *dp)
  146. {
  147. Dirtab *tab;
  148. int len, type;
  149. Qid qid;
  150. type = TYPE(c->qid.path);
  151. if(i == DEVDOTDOT){
  152. switch(type){
  153. case Qtopdir:
  154. case Qloopdir:
  155. snprint(up->genbuf, sizeof(up->genbuf), "#X%ld", c->dev);
  156. mkqid(&qid, QID(0, Qtopdir), 0, QTDIR);
  157. devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
  158. break;
  159. case Qportdir:
  160. snprint(up->genbuf, sizeof(up->genbuf), "loopback%ld", c->dev);
  161. mkqid(&qid, QID(0, Qloopdir), 0, QTDIR);
  162. devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
  163. break;
  164. default:
  165. panic("loopbackgen %llux", c->qid.path);
  166. }
  167. return 1;
  168. }
  169. switch(type){
  170. case Qtopdir:
  171. if(i != 0)
  172. return -1;
  173. snprint(up->genbuf, sizeof(up->genbuf), "loopback%ld", c->dev);
  174. mkqid(&qid, QID(0, Qloopdir), 0, QTDIR);
  175. devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
  176. return 1;
  177. case Qloopdir:
  178. if(i >= 2)
  179. return -1;
  180. snprint(up->genbuf, sizeof(up->genbuf), "%d", i);
  181. mkqid(&qid, QID(i, QID(0, Qportdir)), 0, QTDIR);
  182. devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
  183. return 1;
  184. case Qportdir:
  185. if(i >= nelem(loopportdir))
  186. return -1;
  187. tab = &loopportdir[i];
  188. mkqid(&qid, QID(ID(c->qid.path), tab->qid.path), 0, QTFILE);
  189. devdir(c, qid, tab->name, tab->length, eve, tab->perm, dp);
  190. return 1;
  191. default:
  192. /* non directory entries end up here; must be in lowest level */
  193. if(c->qid.type & QTDIR)
  194. panic("loopbackgen: unexpected directory");
  195. if(i != 0)
  196. return -1;
  197. tab = &loopdirs[type];
  198. if(tab == nil)
  199. panic("loopbackgen: unknown type: %d", type);
  200. len = tab->length;
  201. devdir(c, c->qid, tab->name, len, eve, tab->perm, dp);
  202. return 1;
  203. }
  204. }
  205. static Walkqid*
  206. loopbackwalk(Chan *c, Chan *nc, char **name, int nname)
  207. {
  208. Walkqid *wq;
  209. Loop *lb;
  210. wq = devwalk(c, nc, name, nname, nil, 0, loopbackgen);
  211. if(wq != nil && wq->clone != nil && wq->clone != c){
  212. lb = c->aux;
  213. qlock(lb);
  214. lb->ref++;
  215. if((c->flag & COPEN) && TYPE(c->qid.path) == Qdata)
  216. lb->link[ID(c->qid.path)].ref++;
  217. qunlock(lb);
  218. }
  219. return wq;
  220. }
  221. static int
  222. loopbackstat(Chan *c, uchar *db, int n)
  223. {
  224. return devstat(c, db, n, nil, 0, loopbackgen);
  225. }
  226. /*
  227. * if the stream doesn't exist, create it
  228. */
  229. static Chan*
  230. loopbackopen(Chan *c, int omode)
  231. {
  232. Loop *lb;
  233. if(c->qid.type & QTDIR){
  234. if(omode != OREAD)
  235. error(Ebadarg);
  236. c->mode = omode;
  237. c->flag |= COPEN;
  238. c->offset = 0;
  239. return c;
  240. }
  241. lb = c->aux;
  242. qlock(lb);
  243. if(TYPE(c->qid.path) == Qdata){
  244. if(lb->link[ID(c->qid.path)].ref){
  245. qunlock(lb);
  246. error(Einuse);
  247. }
  248. lb->link[ID(c->qid.path)].ref++;
  249. }
  250. qunlock(lb);
  251. c->mode = openmode(omode);
  252. c->flag |= COPEN;
  253. c->offset = 0;
  254. c->iounit = qiomaxatomic;
  255. return c;
  256. }
  257. static void
  258. loopbackclose(Chan *c)
  259. {
  260. Loop *lb;
  261. int ref, chan;
  262. lb = c->aux;
  263. qlock(lb);
  264. /*
  265. * closing either side hangs up the stream
  266. */
  267. if((c->flag & COPEN) && TYPE(c->qid.path) == Qdata){
  268. chan = ID(c->qid.path);
  269. if(--lb->link[chan].ref == 0){
  270. qhangup(lb->link[chan ^ 1].oq, nil);
  271. looper(lb);
  272. }
  273. }
  274. /*
  275. * if both sides are closed, they are reusable
  276. */
  277. if(lb->link[0].ref == 0 && lb->link[1].ref == 0){
  278. for(chan = 0; chan < 2; chan++){
  279. closelink(&lb->link[chan], 0);
  280. qreopen(lb->link[chan].iq);
  281. qreopen(lb->link[chan].oq);
  282. qsetlimit(lb->link[chan].oq, lb->link[chan].limit);
  283. qsetlimit(lb->link[chan].iq, lb->link[chan].limit);
  284. }
  285. }
  286. ref = --lb->ref;
  287. if(ref == 0)
  288. freelb(lb);
  289. qunlock(lb);
  290. }
  291. static void
  292. freelb(Loop *lb)
  293. {
  294. int chan;
  295. for(chan = 0; chan < 2; chan++)
  296. closelink(&lb->link[chan], 1);
  297. }
  298. /*
  299. * called with the Loop qlocked,
  300. * so only pushlink can mess with the queues
  301. */
  302. static void
  303. closelink(Link *link, int dofree)
  304. {
  305. Queue *iq, *oq;
  306. Block *bp;
  307. ilock(link);
  308. iq = link->iq;
  309. oq = link->oq;
  310. bp = link->tq;
  311. link->tq = nil;
  312. link->tqtail = nil;
  313. link->tout = 0;
  314. link->tin = 0;
  315. timerdel(&link->ci);
  316. iunlock(link);
  317. if(iq != nil){
  318. qclose(iq);
  319. if(dofree){
  320. ilock(link);
  321. free(iq);
  322. link->iq = nil;
  323. iunlock(link);
  324. }
  325. }
  326. if(oq != nil){
  327. qclose(oq);
  328. if(dofree){
  329. ilock(link);
  330. free(oq);
  331. link->oq = nil;
  332. iunlock(link);
  333. }
  334. }
  335. freeblist(bp);
  336. }
  337. static long
  338. loopbackread(Chan *c, void *va, long n, vlong offset)
  339. {
  340. Loop *lb;
  341. Link *link;
  342. char *buf;
  343. long rv;
  344. lb = c->aux;
  345. switch(TYPE(c->qid.path)){
  346. default:
  347. error(Eperm);
  348. return -1; /* not reached */
  349. case Qtopdir:
  350. case Qloopdir:
  351. case Qportdir:
  352. return devdirread(c, va, n, nil, 0, loopbackgen);
  353. case Qdata:
  354. return qread(lb->link[ID(c->qid.path)].iq, va, n);
  355. case Qstatus:
  356. link = &lb->link[ID(c->qid.path)];
  357. buf = smalloc(Statelen);
  358. rv = snprint(buf, Statelen, "delay %lld %ld\n", link->delay0ns, link->delaynns);
  359. rv += snprint(buf+rv, Statelen-rv, "limit %ld\n", link->limit);
  360. rv += snprint(buf+rv, Statelen-rv, "indrop %d\n", link->indrop);
  361. snprint(buf+rv, Statelen-rv, "droprate %ld\n", link->droprate);
  362. rv = readstr(offset, va, n, buf);
  363. free(buf);
  364. break;
  365. case Qstats:
  366. link = &lb->link[ID(c->qid.path)];
  367. buf = smalloc(Statelen);
  368. rv = snprint(buf, Statelen, "packets: %ld\n", link->packets);
  369. rv += snprint(buf+rv, Statelen-rv, "bytes: %ld\n", link->bytes);
  370. rv += snprint(buf+rv, Statelen-rv, "dropped: %ld\n", link->drops);
  371. snprint(buf+rv, Statelen-rv, "soft overflows: %ld\n", link->soverflows);
  372. rv = readstr(offset, va, n, buf);
  373. free(buf);
  374. break;
  375. }
  376. return rv;
  377. }
  378. static Block*
  379. loopbackbread(Chan *c, long n, ulong offset)
  380. {
  381. Loop *lb;
  382. lb = c->aux;
  383. if(TYPE(c->qid.path) == Qdata)
  384. return qbread(lb->link[ID(c->qid.path)].iq, n);
  385. return devbread(c, n, offset);
  386. }
  387. static long
  388. loopbackbwrite(Chan *c, Block *bp, ulong off)
  389. {
  390. Loop *lb;
  391. lb = c->aux;
  392. if(TYPE(c->qid.path) == Qdata)
  393. return loopoput(lb, &lb->link[ID(c->qid.path) ^ 1], bp);
  394. return devbwrite(c, bp, off);
  395. }
  396. static long
  397. loopbackwrite(Chan *c, void *va, long n, vlong off)
  398. {
  399. Loop *lb;
  400. Link *link;
  401. Cmdbuf *volatile cb;
  402. Block *volatile bp;
  403. vlong d0, d0ns;
  404. long dn, dnns;
  405. switch(TYPE(c->qid.path)){
  406. case Qdata:
  407. bp = allocb(n);
  408. if(waserror()){
  409. freeb(bp);
  410. nexterror();
  411. }
  412. memmove(bp->wp, va, n);
  413. poperror();
  414. bp->wp += n;
  415. return loopbackbwrite(c, bp, off);
  416. case Qctl:
  417. lb = c->aux;
  418. link = &lb->link[ID(c->qid.path)];
  419. cb = parsecmd(va, n);
  420. if(waserror()){
  421. free(cb);
  422. nexterror();
  423. }
  424. if(cb->nf < 1)
  425. error("short control request");
  426. if(strcmp(cb->f[0], "delay") == 0){
  427. if(cb->nf != 3)
  428. error("usage: delay latency bytedelay");
  429. d0ns = strtoll(cb->f[1], nil, 10);
  430. dnns = strtol(cb->f[2], nil, 10);
  431. /*
  432. * it takes about 20000 cycles on a pentium ii
  433. * to run pushlink; perhaps this should be accounted.
  434. */
  435. ilock(link);
  436. link->delay0ns = d0ns;
  437. link->delaynns = dnns;
  438. iunlock(link);
  439. }else if(strcmp(cb->f[0], "indrop") == 0){
  440. if(cb->nf != 2)
  441. error("usage: indrop [01]");
  442. ilock(link);
  443. link->indrop = strtol(cb->f[1], nil, 0) != 0;
  444. iunlock(link);
  445. }else if(strcmp(cb->f[0], "droprate") == 0){
  446. if(cb->nf != 2)
  447. error("usage: droprate ofn");
  448. ilock(link);
  449. link->droprate = strtol(cb->f[1], nil, 0);
  450. iunlock(link);
  451. }else if(strcmp(cb->f[0], "limit") == 0){
  452. if(cb->nf != 2)
  453. error("usage: limit maxqsize");
  454. ilock(link);
  455. link->limit = strtol(cb->f[1], nil, 0);
  456. qsetlimit(link->oq, link->limit);
  457. qsetlimit(link->iq, link->limit);
  458. iunlock(link);
  459. }else if(strcmp(cb->f[0], "reset") == 0){
  460. if(cb->nf != 1)
  461. error("usage: reset");
  462. ilock(link);
  463. link->packets = 0;
  464. link->bytes = 0;
  465. link->indrop = 0;
  466. link->soverflows = 0;
  467. link->drops = 0;
  468. iunlock(link);
  469. }else
  470. error("unknown control request");
  471. poperror();
  472. free(cb);
  473. break;
  474. default:
  475. error(Eperm);
  476. }
  477. return n;
  478. }
  479. static long
  480. loopoput(Loop *lb, Link *link, Block *volatile bp)
  481. {
  482. long n;
  483. n = BLEN(bp);
  484. /* make it a single block with space for the loopback timing header */
  485. if(waserror()){
  486. freeb(bp);
  487. nexterror();
  488. }
  489. bp = padblock(bp, Tmsize);
  490. if(bp->next)
  491. bp = concatblock(bp);
  492. if(BLEN(bp) < lb->minmtu)
  493. bp = adjustblock(bp, lb->minmtu);
  494. poperror();
  495. ptime(bp->rp, todget(nil));
  496. link->packets++;
  497. link->bytes += n;
  498. qbwrite(link->oq, bp);
  499. looper(lb);
  500. return n;
  501. }
  502. static void
  503. looper(Loop *lb)
  504. {
  505. vlong t;
  506. int chan;
  507. t = todget(nil);
  508. for(chan = 0; chan < 2; chan++)
  509. pushlink(&lb->link[chan], t);
  510. }
  511. static void
  512. linkintr(Ureg*, Timer *ci)
  513. {
  514. Link *link;
  515. link = ci->a;
  516. pushlink(link, ci->ns);
  517. }
  518. /*
  519. * move blocks between queues if they are ready.
  520. * schedule an interrupt for the next interesting time.
  521. *
  522. * must be called with the link ilocked.
  523. */
  524. static void
  525. pushlink(Link *link, vlong now)
  526. {
  527. Block *bp;
  528. vlong tout, tin;
  529. /*
  530. * put another block in the link queue
  531. */
  532. ilock(link);
  533. if(link->iq == nil || link->oq == nil){
  534. iunlock(link);
  535. return;
  536. }
  537. timerdel(&link->ci);
  538. /*
  539. * put more blocks into the xmit queue
  540. * use the time the last packet was supposed to go out
  541. * as the start time for the next packet, rather than
  542. * the current time. this more closely models a network
  543. * device which can queue multiple output packets.
  544. */
  545. tout = link->tout;
  546. if(!tout)
  547. tout = now;
  548. while(tout <= now){
  549. bp = qget(link->oq);
  550. if(bp == nil){
  551. tout = 0;
  552. break;
  553. }
  554. /*
  555. * can't send the packet before it gets queued
  556. */
  557. tin = gtime(bp->rp);
  558. if(tin > tout)
  559. tout = tin;
  560. tout = tout + (BLEN(bp) - Tmsize) * link->delayn;
  561. /*
  562. * drop packets
  563. */
  564. if(link->droprate && nrand(link->droprate) == 0)
  565. link->drops++;
  566. else{
  567. ptime(bp->rp, tout + link->delay0ns);
  568. if(link->tq == nil)
  569. link->tq = bp;
  570. else
  571. link->tqtail->next = bp;
  572. link->tqtail = bp;
  573. }
  574. }
  575. /*
  576. * record the next time a packet can be sent,
  577. * but don't schedule an interrupt if none is waiting
  578. */
  579. link->tout = tout;
  580. if(!qcanread(link->oq))
  581. tout = 0;
  582. /*
  583. * put more blocks into the receive queue
  584. */
  585. tin = 0;
  586. while(bp = link->tq){
  587. tin = gtime(bp->rp);
  588. if(tin > now)
  589. break;
  590. bp->rp += Tmsize;
  591. link->tq = bp->next;
  592. bp->next = nil;
  593. if(!link->indrop)
  594. qpassnolim(link->iq, bp);
  595. else if(qpass(link->iq, bp) < 0)
  596. link->soverflows++;
  597. tin = 0;
  598. }
  599. if(bp == nil && qisclosed(link->oq) && !qcanread(link->oq) && !qisclosed(link->iq))
  600. qhangup(link->iq, nil);
  601. link->tin = tin;
  602. if(!tin || tin > tout && tout)
  603. tin = tout;
  604. link->ci.ns = tin - now;
  605. if(tin){
  606. if(tin < now)
  607. panic("loopback unfinished business");
  608. timeradd(&link->ci);
  609. }
  610. iunlock(link);
  611. }
  612. static void
  613. ptime(uchar *p, vlong t)
  614. {
  615. ulong tt;
  616. tt = t >> 32;
  617. p[0] = tt >> 24;
  618. p[1] = tt >> 16;
  619. p[2] = tt >> 8;
  620. p[3] = tt;
  621. tt = t;
  622. p[4] = tt >> 24;
  623. p[5] = tt >> 16;
  624. p[6] = tt >> 8;
  625. p[7] = tt;
  626. }
  627. static vlong
  628. gtime(uchar *p)
  629. {
  630. ulong t1, t2;
  631. t1 = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
  632. t2 = (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7];
  633. return ((vlong)t1 << 32) | t2;
  634. }
  635. Dev loopbackdevtab = {
  636. 'X',
  637. "loopback",
  638. devreset,
  639. loopbackinit,
  640. devshutdown,
  641. loopbackattach,
  642. loopbackwalk,
  643. loopbackstat,
  644. loopbackopen,
  645. devcreate,
  646. loopbackclose,
  647. loopbackread,
  648. loopbackbread,
  649. loopbackwrite,
  650. loopbackbwrite,
  651. devremove,
  652. devwstat,
  653. };