net: tcp: Fix TSO for incoming connections
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 8 Nov 2017 19:43:45 +0000 (14:43 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 16 Nov 2017 15:46:56 +0000 (10:46 -0500)
TSO was only being used on outbound connections.  The issue was that the
'flags' in tcpmtu for inbound connections was seg.flags, not tcb->flags.
So that bit we were setting was discarded.

The fix is to do the lookup (which requires the ifc) once we finally have
the tcb, which is after the conversation comes out of limbo.  Instead of
looking up the ifc twice, we can just store the uncounted ref.  We'll
probably have other uses for the ifc.

Note that the ifc->feat is not exactly the same as ether->netif->feat.  The
device's features are copied over to the IP interface during etherbind.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/include/net/tcp.h
kern/src/net/tcp.c

index 4530879..309d375 100644 (file)
@@ -281,6 +281,7 @@ struct tcpctl {
        uint32_t ts_recent;                     /* timestamp received around last_ack_sent */
        uint32_t last_ack_sent;         /* to determine when to update timestamp */
        bool sack_ok;                           /* Can use SACK for this connection */
+       struct Ipifc *ifc;                      /* Uncounted ref */
 
        union {
                Tcp4hdr tcp4hdr;
@@ -318,6 +319,7 @@ struct limbo {
        uint8_t rexmits;                        /* number of retransmissions */
        bool sack_ok;                           /* other side said SACK_OK */
        uint32_t ts_val;                        /* timestamp val from sender */
+       struct Ipifc *ifc;                      /* Uncounted ref */
 };
 
 enum {
index 208b1ce..7ad7ef0 100644 (file)
@@ -491,13 +491,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 +508,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 +583,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 +593,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);
 }
 
 /*
@@ -1019,8 +1026,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,
@@ -1192,12 +1198,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;
@@ -1491,9 +1498,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;