qio: Track the amount of bytes read
[akaros.git] / kern / src / net / devip.c
index 38e3b74..410f94d 100644 (file)
@@ -84,6 +84,7 @@ enum {
 
        Nfs = 32,
        BYPASS_QMAX = 64 * MiB,
+       IPROUTE_LEN = 2 * PGSIZE,
 };
 #define TYPE(x)        ( ((uint32_t)(x).path) & Masktype )
 #define CONV(x)        ( (((uint32_t)(x).path) >> Shiftconv) & Maskconv )
@@ -97,7 +98,7 @@ struct queue *qlog;
 
 extern void nullmediumlink(void);
 extern void pktmediumlink(void);
-extern char *eve;
+extern struct username eve;
 static long ndbwrite(struct Fs *, char *unused_char_p_t, uint32_t, int);
 static void closeconv(struct conv *);
 static void setup_proto_qio_bypass(struct conv *cv);
@@ -135,7 +136,7 @@ static int ip3gen(struct chan *c, int i, struct dir *dp)
 
        cv = chan2conv(c);
        if (cv->owner == NULL)
-               kstrdup(&cv->owner, eve);
+               kstrdup(&cv->owner, eve.name);
        mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE);
 
        switch (i) {
@@ -156,7 +157,9 @@ static int ip3gen(struct chan *c, int i, struct dir *dp)
                        return founddevdir(c, q, "err", qlen(cv->eq),
                                                           cv->owner, perm, dp);
                case Qlisten:
-                       return founddevdir(c, q, "listen", 0, cv->owner, cv->perm, dp);
+                       perm = cv->perm;
+                       perm |= cv->incall ? DMREADABLE : 0;
+                       return founddevdir(c, q, "listen", 0, cv->owner, perm, dp);
                case Qlocal:
                        p = "local";
                        break;
@@ -435,6 +438,8 @@ static struct chan *ipopen(struct chan *c, int omode)
                        iprouteropen(f);
                        break;
                case Qiproute:
+                       c->synth_buf = kpages_zalloc(IPROUTE_LEN, MEM_WAIT);
+                       routeread(f, c->synth_buf, 0, IPROUTE_LEN);
                        break;
                case Qtopdir:
                case Qprotodir:
@@ -468,7 +473,7 @@ static struct chan *ipopen(struct chan *c, int omode)
                        qunlock(&p->qlock);
                        poperror();
                        if (cv == NULL) {
-                               error(ENODEV, ERROR_FIXME);
+                               error(ENODEV, "Null conversation from Fsprotoclone");
                                break;
                        }
                        mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE);
@@ -613,7 +618,7 @@ static int ipwstat(struct chan *c, uint8_t * dp, int n)
                error(EPERM, ERROR_FIXME);
        if (!emptystr(d->uid))
                kstrdup(&cv->owner, d->uid);
-       if (d->mode != ~0UL)
+       if (d->mode != -1)
                cv->perm = d->mode & 0777;
        poperror();
        kfree(d);
@@ -637,9 +642,11 @@ static char *ipchaninfo(struct chan *ch, char *ret, size_t ret_l)
                case Qdata:
                        proto = f->p[PROTO(ch->qid)];
                        conv = proto->conv[CONV(ch->qid)];
-                       snprintf(ret, ret_l, "Qdata, %s, proto %s, conv idx %d, rq len %d, wq len %d",
+                       snprintf(ret, ret_l,
+                                "Qdata, %s, proto %s, conv idx %d, rq len %d, wq len %d, total read %llu",
                                 SLIST_EMPTY(&conv->data_taps) ? "untapped" : "tapped",
-                                proto->name, conv->x, qlen(conv->rq), qlen(conv->wq));
+                                proto->name, conv->x, qlen(conv->rq), qlen(conv->wq),
+                                        q_bytes_read(conv->rq));
                        break;
                case Qarp:
                        ret = "Qarp";
@@ -650,9 +657,10 @@ static char *ipchaninfo(struct chan *ch, char *ret, size_t ret_l)
                case Qlisten:
                        proto = f->p[PROTO(ch->qid)];
                        conv = proto->conv[CONV(ch->qid)];
-                       snprintf(ret, ret_l, "Qlisten, %s proto %s, conv idx %d",
+                       snprintf(ret, ret_l,
+                                "Qlisten, %s proto %s, conv idx %d, has %sincalls",
                                 SLIST_EMPTY(&conv->listen_taps) ? "untapped" : "tapped",
-                                proto->name, conv->x);
+                                proto->name, conv->x, conv->incall ? "" : "no ");
                        break;
                case Qlog:
                        ret = "Qlog";
@@ -736,6 +744,10 @@ static void ipclose(struct chan *c)
                        if (c->flag & COPEN)
                                atomic_dec(&f->p[PROTO(c->qid)]->conv[CONV(c->qid)]->snoopers);
                        break;
+               case Qiproute:
+                       if (c->flag & COPEN)
+                               kpages_free(c->synth_buf, IPROUTE_LEN);
+                       break;
        }
        kfree(((struct IPaux *)c->aux)->owner);
        kfree(c->aux);
@@ -769,7 +781,7 @@ static long ipread(struct chan *ch, void *a, long n, int64_t off)
                case Qndb:
                        return readstr(offset, a, n, f->ndb);
                case Qiproute:
-                       return routeread(f, a, offset, n);
+                       return readmem(offset, a, n, ch->synth_buf, IPROUTE_LEN);
                case Qiprouter:
                        return iprouterread(f, a, n);
                case Qipselftab:
@@ -1036,12 +1048,18 @@ void Fsstdconnect(struct conv *c, char *argv[], int argc)
                        break;
        }
 
+       /* TODO: why is an IPnoaddr (in v6 format, equivalent to v6Unspecified),
+        * a v4 format? */
        if ((memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
                 memcmp(c->laddr, v4prefix, IPv4off) == 0)
                || ipcmp(c->raddr, IPnoaddr) == 0)
                c->ipversion = V4;
        else
                c->ipversion = V6;
+       /* Linux has taught people to use zeros for local interfaces.  TODO: We
+        * might need this for v6 in the future. */
+       if (!ipcmp(c->raddr, IPv4_zeroes))
+               ipmove(c->raddr, IPv4_loopback);
 }
 
 /*
@@ -1321,6 +1339,22 @@ static void ttlctlmsg(struct conv *c, struct cmdbuf *cb)
                c->ttl = atoi(cb->f[1]);
 }
 
+/* Binds a conversation, as if the user wrote "bind *" into ctl. */
+static void autobind(struct conv *cv)
+{
+       ERRSTACK(1);
+       struct cmdbuf *cb;
+
+       cb = parsecmd("bind *", 7);
+       if (waserror()) {
+               kfree(cb);
+               nexterror();
+       }
+       bindctlmsg(cv->p, cv, cb);
+       poperror();
+       kfree(cb);
+}
+
 static long ipwrite(struct chan *ch, void *v, long n, int64_t off)
 {
        ERRSTACK(1);
@@ -1341,6 +1375,10 @@ static long ipwrite(struct chan *ch, void *v, long n, int64_t off)
                case Qdata:
                        x = f->p[PROTO(ch->qid)];
                        c = x->conv[CONV(ch->qid)];
+                       /* connection-less protocols (UDP) can write without manually
+                        * binding. */
+                       if (c->lport == 0)
+                               autobind(c);
                        if (ch->flag & O_NONBLOCK)
                                qwrite_nonblock(c->wq, a, n);
                        else
@@ -1626,7 +1664,9 @@ retry:
                if (c == NULL) {
                        c = kzmalloc(sizeof(struct conv), 0);
                        if (c == NULL)
-                               error(ENOMEM, ERROR_FIXME);
+                               error(ENOMEM,
+                                     "conv kzmalloc(%d, 0) failed in Fsprotoclone",
+                                     sizeof(struct conv));
                        qlock_init(&c->qlock);
                        qlock_init(&c->listenq);
                        rendez_init(&c->cr);
@@ -1641,7 +1681,9 @@ retry:
                                c->ptcl = kzmalloc(p->ptclsize, 0);
                                if (c->ptcl == NULL) {
                                        kfree(c);
-                                       error(ENOMEM, ERROR_FIXME);
+                                       error(ENOMEM,
+                                             "ptcl kzmalloc(%d, 0) failed in Fsprotoclone",
+                                             p->ptclsize);
                                }
                        }
                        *pp = c;