net: Clarify transport checksum offload
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 10 Nov 2017 17:14:50 +0000 (12:14 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 16 Nov 2017 15:46:56 +0000 (10:46 -0500)
It turns out that checksum_start (an offset) was always the same as
transport_offset.  That's how these transport xsum offloads work.

The asserts are for sanity checks.  We can take those out once we're sure
I'm right about all this.

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

index 711f8e7..2c1f42d 100644 (file)
@@ -676,20 +676,28 @@ extern void ip_init(struct Fs *);
 extern void update_mtucache(uint8_t * unused_uint8_p_t, uint32_t);
 extern uint32_t restrict_mtu(uint8_t * unused_uint8_p_t, uint32_t);
 
+/* We support transport layer checksum offloading.  If a NIC doesn't support
+ * it, we'll finish it in software here.
+ *
+ * We've checksummed pseudo header in advance.  The remaining bits that need to
+ * be csummed is the entire transport layer (header + data).  The NICs (and
+ * this function) expect the PH to be done already and stored in the transport
+ * layer's csum location.  This function wants to know where that is in a
+ * protocol-independent manner, hence the tx_csum_offset. */
 static inline void ptclcsum_finalize(struct block *bp, unsigned int feat)
 {
        unsigned int flag = bp->flag & BCKSUM_FLAGS;
        uint8_t *csum_store;
 
        if (flag && (flag & feat) != flag) {
-               csum_store = bp->rp + bp->checksum_start + bp->checksum_offset;
+               csum_store = bp->rp + bp->transport_offset + bp->tx_csum_offset;
                /* NOTE pseudo-header partial checksum (if any) is already placed at
                 * csum_store (e.g. tcpcksum), and the ptclcsum() below will include
                 * that partial checksum as part of the calculation.
                 */
                hnputs((uint16_t *)csum_store,
-                      ptclcsum(bp, bp->checksum_start,
-                               BLEN(bp) - bp->checksum_start));
+                      ptclcsum(bp, bp->transport_offset,
+                               BLEN(bp) - bp->transport_offset));
                bp->flag &= ~BCKSUM_FLAGS;
        }
 }
index 309d375..f88d7f3 100644 (file)
@@ -145,9 +145,12 @@ struct tcphdr {
        uint8_t tcpopt[1];
 };
 
-/*
- *  v4 and v6 pseudo headers used for
- *  checksuming tcp
+/* v4 and v6 pseudo headers used for checksumming tcp
+ *
+ * Note the field layout is the same for a real IP packet.  "Unused" in v4 is
+ * the TTL slot, but it's the 'zeros' for the TCP PH csum.  Similarly, tcplen is
+ * the IP csum slot.  Later on, it'll get overwritten in the IP stack or in
+ * hardware.  The struct tcp4hdr (or rather bp->rp) will be cast to an Ip4hdr.
  */
 typedef struct tcp4hdr Tcp4hdr;
 struct tcp4hdr {
index 67a2925..28b1763 100644 (file)
@@ -383,11 +383,10 @@ struct block {
        uint8_t *base;                          /* start of the buffer */
        void (*free) (struct block *);
        uint16_t flag;
-       uint16_t checksum_start;                /* off from start of block to start csum */
-       uint16_t checksum_offset;               /* off from checksum_start to store csum */
        uint16_t mss;               /* TCP MSS for TSO */
        uint16_t network_offset;        /* offset from start */
        uint16_t transport_offset;      /* offset from start */
+       uint16_t tx_csum_offset;        /* offset from tx_offset to store csum */
        /* might want something to track the next free extra_data slot */
        size_t extra_len;
        unsigned int nr_extra_bufs;
index 37842e9..d814777 100644 (file)
@@ -249,6 +249,9 @@ ipoput4(struct Fs *f,
 
        ip = f->ip;
 
+       /* Sanity check for our transport protocols. */
+       if (bp->mss)
+               assert(bp->flag & Btso);
        /* Fill out the ip header */
        eh = (struct Ip4hdr *)(bp->rp);
 
index 0b5118c..163b533 100644 (file)
@@ -163,6 +163,9 @@ int ipoput6(struct Fs *f, struct block *bp,
 
        ip = f->ip;
 
+       /* Sanity check for our transport protocols. */
+       if (bp->mss)
+               assert(bp->flag & Btso);
        /* Fill out the ip header */
        eh = (struct ip6hdr *)(bp->rp);
 
index 7ad7ef0..887057c 100644 (file)
@@ -855,10 +855,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;
        }
 
index 146a6ce..ecc941e 100644 (file)
@@ -327,12 +327,12 @@ void udpkick(void *x, struct block *bp)
                        hnputs(uh4->udplen, ptcllen);
                        uh4->udpcksum[0] = 0;
                        uh4->udpcksum[1] = 0;
-                       hnputs(uh4->udpcksum,
-                                  ~ptclcsum(bp, UDP4_PHDR_OFF, UDP4_PHDR_SZ));
-                       bp->checksum_start = UDP4_IPHDR_SZ;
-                       bp->checksum_offset = uh4->udpcksum - uh4->udpsport;
                        bp->network_offset = 0;
                        bp->transport_offset = offsetof(Udp4hdr, udpsport);
+                       assert(bp->transport_offset == UDP4_IPHDR_SZ);
+                       hnputs(uh4->udpcksum,
+                                  ~ptclcsum(bp, UDP4_PHDR_OFF, UDP4_PHDR_SZ));
+                       bp->tx_csum_offset = uh4->udpcksum - uh4->udpsport;
                        bp->flag |= Budpck;
                        uh4->vihl = IP_VER4;
                        ipoput4(f, bp, 0, c->ttl, c->tos, rc);
index 68731e5..2998f84 100644 (file)
@@ -132,8 +132,7 @@ struct block *padblock(struct block *bp, int size)
        int n;
        struct block *nbp;
        uint8_t bcksum = bp->flag & BCKSUM_FLAGS;
-       uint16_t checksum_start = bp->checksum_start;
-       uint16_t checksum_offset = bp->checksum_offset;
+       uint16_t tx_csum_offset = bp->tx_csum_offset;
        uint16_t mss = bp->mss;
        uint16_t network_offset = bp->network_offset;
        uint16_t transport_offset = bp->transport_offset;
@@ -141,7 +140,6 @@ struct block *padblock(struct block *bp, int size)
        QDEBUG checkb(bp, "padblock 1");
        if (size >= 0) {
                if (bp->rp - bp->base >= size) {
-                       bp->checksum_start += size;
                        bp->network_offset += size;
                        bp->transport_offset += size;
                        bp->rp -= size;
@@ -180,8 +178,7 @@ struct block *padblock(struct block *bp, int size)
        }
        if (bcksum) {
                nbp->flag |= bcksum;
-               nbp->checksum_start = checksum_start;
-               nbp->checksum_offset = checksum_offset;
+               nbp->tx_csum_offset = tx_csum_offset;
                nbp->mss = mss;
                nbp->network_offset = network_offset;
                nbp->transport_offset = transport_offset;
@@ -272,8 +269,7 @@ struct block *copyblock(struct block *bp, int mem_flags)
        /* TODO: any other flags that need copied over? */
        if (bp->flag & BCKSUM_FLAGS) {
                newb->flag |= (bp->flag & BCKSUM_FLAGS);
-               newb->checksum_start = bp->checksum_start;
-               newb->checksum_offset = bp->checksum_offset;
+               newb->tx_csum_offset = bp->tx_csum_offset;
                newb->mss = bp->mss;
                newb->network_offset = bp->network_offset;
                newb->transport_offset = bp->transport_offset;