WIP-pop-3000
[akaros.git] / kern / src / net / tcp.c
index 2954840..0f9c4ac 100644 (file)
@@ -399,6 +399,37 @@ static void tcpackproc(void *a)
                        if (loop++ > 10000)
                                panic("tcpackproc1");
                        tp = t->next;
+                       /* this is a little odd.  overall, we wake up once per 'tick' (50ms,
+                        * whatever).  then, we decrement count.  so the timer val is in
+                        * units of 50 ms.  the timer list isn't sorted either.  once
+                        * someone expires, we get moved to another LL, local, and we fire
+                        * those alarms.
+                        *
+                        * the best anyone could do would be 50 ms granularity.
+                        *
+                        * if things are slow, you could skew later too.
+                        *
+                        * actually, you're expected value is 25ms for the first count.  so
+                        * whatever your timer.start is, your wait time is start * 50 - 25.
+                        *              which is why we wait 25 ms to open up our window again.
+                        *
+                        * might be issues with concurrency.  once the alarm is set to done
+                        * and yanked off the list, what's to stop a concurrent setter from
+                        * putting it back on the list and setting TcptimerON?
+                        *              there's a lot of lockless peeks at the timer.state
+                        *
+                        * probably be better served with a kthread timer chain
+                        *              one assumption with the timerchain stuff is that the source
+                        *              is an IRQ, and thus IRQ context matters, etc.
+                        *
+                        *              with a kth tchain, we're in kth context already.  and you
+                        *              probably don't want to send another RKM for each timer.
+                        *              unless the locking matters.
+                        *
+                        *              interesting - even the pcpu tchains - should those be a
+                        *              per-core kth?  does any alarm need to run from IRQ ctx?
+                        *                              maybe.
+                        * */
                        if (t->state == TcptimerON) {
                                t->count--;
                                if (t->count == 0) {
@@ -491,13 +522,10 @@ static void localclose(struct conv *s, char *reason)
 }
 
 /* mtu (- TCP + IP hdr len) of 1st hop */
-static int tcpmtu(struct Proto *tcp, uint8_t *addr, int version, int *scale,
-                  uint8_t *flags)
+static int tcpmtu(struct Ipifc *ifc, int version, int *scale)
 {
-       struct Ipifc *ifc;
        int mtu;
 
-       ifc = findipifc(tcp->f, addr, 0);
        switch (version) {
                default:
                case V4:
@@ -511,14 +539,22 @@ static int tcpmtu(struct Proto *tcp, uint8_t *addr, int version, int *scale,
                                mtu = ifc->maxtu - ifc->m->hsize - (TCP6_PKT + TCP6_HDRSIZE);
                        break;
        }
-       *flags &= ~TSO;
-       if (ifc && (ifc->feat & NETF_TSO))
-               *flags |= TSO;
        *scale = HaveWS | 7;
 
        return mtu;
 }
 
+static void tcb_check_tso(Tcpctl *tcb)
+{
+       /* This can happen if the netdev isn't up yet. */
+       if (!tcb->ifc)
+               return;
+       if (tcb->ifc->feat & NETF_TSO)
+               tcb->flags |= TSO;
+       else
+               tcb->flags &= ~TSO;
+}
+
 static void inittcpctl(struct conv *s, int mode)
 {
        Tcpctl *tcb;
@@ -578,6 +614,7 @@ static void inittcpctl(struct conv *s, int mode)
                }
        }
 
+       tcb->ifc = findipifc(s->p->f, s->laddr, 0);
        tcb->mss = mss;
        tcb->typical_mss = mss;
        tcb->cwind = tcb->typical_mss * CWIND_SCALE;
@@ -587,6 +624,7 @@ static void inittcpctl(struct conv *s, int mode)
        tcb->rcv.wnd = QMAX;
        tcb->rcv.scale = 0;
        tcb->snd.scale = 0;
+       tcb_check_tso(tcb);
 }
 
 /*
@@ -776,8 +814,9 @@ static struct block *htontcp6(Tcp *tcph, struct block *data, Tcp6hdr *ph,
        data = alloc_or_pad_block(data, hdrlen + TCP6_PKT);
        if (data == NULL)
                return NULL;
-       /* relative to the block start (bp->rp) */
-       data->transport_header_end = hdrlen + TCP6_PKT;
+       /* relative to the block start (bp->rp).  Note TCP structs include IP. */
+       data->network_offset = 0;
+       data->transport_offset = offsetof(Tcp6hdr, tcpsport);
 
        /* copy in pseudo ip header plus port numbers */
        h = (Tcp6hdr *) (data->rp);
@@ -826,8 +865,9 @@ static struct block *htontcp4(Tcp *tcph, struct block *data, Tcp4hdr *ph,
        data = alloc_or_pad_block(data, hdrlen + TCP4_PKT);
        if (data == NULL)
                return NULL;
-       /* relative to the block start (bp->rp) */
-       data->transport_header_end = hdrlen + TCP4_PKT;
+       /* relative to the block start (bp->rp).  Note TCP structs include IP. */
+       data->network_offset = 0;
+       data->transport_offset = offsetof(Tcp4hdr, tcpsport);
 
        /* copy in pseudo ip header plus port numbers */
        h = (Tcp4hdr *) (data->rp);
@@ -846,10 +886,10 @@ static struct block *htontcp4(Tcp *tcph, struct block *data, Tcp4hdr *ph,
        if (tcb != NULL && tcb->nochecksum) {
                h->tcpcksum[0] = h->tcpcksum[1] = 0;
        } else {
+               assert(data->transport_offset == TCP4_IPLEN + TCP4_PHDRSIZE);
                csum = ~ptclcsum(data, TCP4_IPLEN, TCP4_PHDRSIZE);
                hnputs(h->tcpcksum, csum);
-               data->checksum_start = TCP4_IPLEN + TCP4_PHDRSIZE;
-               data->checksum_offset = ph->tcpcksum - ph->tcpsport;
+               data->tx_csum_offset = ph->tcpcksum - ph->tcpsport;
                data->flag |= Btcpck;
        }
 
@@ -1017,8 +1057,7 @@ static void tcpsndsyn(struct conv *s, Tcpctl *tcb)
        tcb->sndsyntime = NOW;
 
        /* set desired mss and scale */
-       tcb->mss = tcpmtu(s->p, s->laddr, s->ipversion, &tcb->scale,
-                         &tcb->flags);
+       tcb->mss = tcpmtu(tcb->ifc, s->ipversion, &tcb->scale);
 }
 
 static void sndrst(struct Proto *tcp, uint8_t *source, uint8_t *dest,
@@ -1190,12 +1229,13 @@ static int sndsynack(struct Proto *tcp, Limbo *lp)
                default:
                        panic("sndrst: version %d", lp->version);
        }
+       lp->ifc = findipifc(tcp->f, lp->laddr, 0);
 
        seg.seq = lp->iss;
        seg.ack = lp->irs + 1;
        seg.flags = SYN | ACK;
        seg.urg = 0;
-       seg.mss = tcpmtu(tcp, lp->laddr, lp->version, &scale, &flag);
+       seg.mss = tcpmtu(lp->ifc, lp->version, &scale);
        seg.wnd = QMAX;
        seg.ts_val = lp->ts_val;
        seg.nr_sacks = 0;
@@ -1489,9 +1529,11 @@ static struct conv *tcpincoming(struct conv *s, Tcp *segp, uint8_t *src,
         * actually decided on when we agreed to them in the SYNACK we sent.  We
         * didn't create an actual TCB until now, so we can copy those decisions out
         * of the limbo tracker and into the TCB. */
+       tcb->ifc = lp->ifc;
        tcb->sack_ok = lp->sack_ok;
        /* window scaling */
        tcpsetscale(new, tcb, lp->rcvscale, lp->sndscale);
+       tcb_check_tso(tcb);
 
        tcb->snd.wnd = segp->wnd;
        tcb->cwind = tcb->typical_mss * CWIND_SCALE;
@@ -2118,6 +2160,8 @@ static void track_rcv_sack(Tcpctl *tcb, uint32_t left, uint32_t right)
 
        if (!tcb->sack_ok)
                return;
+       if (left == right)
+               return;
        assert(seq_lt(left, right));
        sack->left = left;
        sack->right = right;