[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [4/5] [NET] back: Add TSO support



Hi:

[NET] back: Add TSO support

This patch adds TCP Segmentation Offload (TSO) support to the backend.
It also advertises this fact through xenbus so that the frontend can
detect this and send through TSO requests only if it is supported.

This is done using an extra request slot which is indicated by a flag
in the first slot.  In future checksum offload can be done in the same
way.

Even though only TSO is supported for now the code actually supports
GSO so it can be applied to any other protocol.  The only missing bit
is the detection of host support for a specific GSO protocol.  Once that
is added we can advertise all supported protocols to the guest.

Signed-off-by: Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx>

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@xxxxxxxxxxxxxxxxxxx>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
diff -r c88ee5ecc39c -r f6d1f558bf1c 
linux-2.6-xen-sparse/drivers/xen/netback/netback.c
--- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c        Tue Jun 27 
21:30:08 2006 +1000
+++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c        Tue Jun 27 
21:30:11 2006 +1000
@@ -43,7 +43,7 @@ static void netif_idx_release(u16 pendin
 static void netif_idx_release(u16 pending_idx);
 static void netif_page_release(struct page *page);
 static void make_tx_response(netif_t *netif, 
-                            u16      id,
+                            netif_tx_request_t *txp,
                             s8       st);
 static int  make_rx_response(netif_t *netif, 
                             u16      id, 
@@ -481,7 +481,7 @@ inline static void net_tx_action_dealloc
 
                netif = pending_tx_info[pending_idx].netif;
 
-               make_tx_response(netif, pending_tx_info[pending_idx].req.id, 
+               make_tx_response(netif, &pending_tx_info[pending_idx].req, 
                                 NETIF_RSP_OKAY);
 
                pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
@@ -490,14 +490,16 @@ inline static void net_tx_action_dealloc
        }
 }
 
-static void netbk_tx_err(netif_t *netif, RING_IDX end)
+static void netbk_tx_err(netif_t *netif, netif_tx_request_t *txp, RING_IDX end)
 {
        RING_IDX cons = netif->tx.req_cons;
 
        do {
-               netif_tx_request_t *txp = RING_GET_REQUEST(&netif->tx, cons);
-               make_tx_response(netif, txp->id, NETIF_RSP_ERROR);
-       } while (++cons < end);
+               make_tx_response(netif, txp, NETIF_RSP_ERROR);
+               if (++cons >= end)
+                       break;
+               txp = RING_GET_REQUEST(&netif->tx, cons);
+       } while (1);
        netif->tx.req_cons = cons;
        netif_schedule_work(netif);
        netif_put(netif);
@@ -508,7 +510,7 @@ static int netbk_count_requests(netif_t 
 {
        netif_tx_request_t *first = txp;
        RING_IDX cons = netif->tx.req_cons;
-       int frags = 1;
+       int frags = 0;
 
        while (txp->flags & NETTXF_more_data) {
                if (frags >= work_to_do) {
@@ -543,7 +545,7 @@ static gnttab_map_grant_ref_t *netbk_get
        skb_frag_t *frags = shinfo->frags;
        netif_tx_request_t *txp;
        unsigned long pending_idx = *((u16 *)skb->data);
-       RING_IDX cons = netif->tx.req_cons + 1;
+       RING_IDX cons = netif->tx.req_cons;
        int i, start;
 
        /* Skip first skb fragment if it is on same page as header fragment. */
@@ -581,7 +583,7 @@ static int netbk_tx_check_mop(struct sk_
        err = mop->status;
        if (unlikely(err)) {
                txp = &pending_tx_info[pending_idx].req;
-               make_tx_response(netif, txp->id, NETIF_RSP_ERROR);
+               make_tx_response(netif, txp, NETIF_RSP_ERROR);
                pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
                netif_put(netif);
        } else {
@@ -614,7 +616,7 @@ static int netbk_tx_check_mop(struct sk_
 
                /* Error on this fragment: respond to client with an error. */
                txp = &pending_tx_info[pending_idx].req;
-               make_tx_response(netif, txp->id, NETIF_RSP_ERROR);
+               make_tx_response(netif, txp, NETIF_RSP_ERROR);
                pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
                netif_put(netif);
 
@@ -668,6 +670,7 @@ static void net_tx_action(unsigned long 
        struct sk_buff *skb;
        netif_t *netif;
        netif_tx_request_t txreq;
+       struct netif_tx_extra txtra;
        u16 pending_idx;
        RING_IDX i;
        gnttab_map_grant_ref_t *mop;
@@ -726,22 +729,37 @@ static void net_tx_action(unsigned long 
                }
                netif->remaining_credit -= txreq.size;
 
+               work_to_do--;
+               netif->tx.req_cons = ++i;
+
+               if (txreq.flags & NETTXF_extra_info) {
+                       if (work_to_do-- <= 0) {
+                               DPRINTK("Missing extra info\n");
+                               netbk_tx_err(netif, &txreq, i);
+                               continue;
+                       }
+
+                       memcpy(&txtra, RING_GET_REQUEST(&netif->tx, i),
+                              sizeof(txtra));
+                       netif->tx.req_cons = ++i;
+               }
+
                ret = netbk_count_requests(netif, &txreq, work_to_do);
                if (unlikely(ret < 0)) {
-                       netbk_tx_err(netif, i - ret);
+                       netbk_tx_err(netif, &txreq, i - ret);
                        continue;
                }
                i += ret;
 
                if (unlikely(ret > MAX_SKB_FRAGS + 1)) {
                        DPRINTK("Too many frags\n");
-                       netbk_tx_err(netif, i);
+                       netbk_tx_err(netif, &txreq, i);
                        continue;
                }
 
                if (unlikely(txreq.size < ETH_HLEN)) {
                        DPRINTK("Bad packet size: %d\n", txreq.size);
-                       netbk_tx_err(netif, i);
+                       netbk_tx_err(netif, &txreq, i);
                        continue; 
                }
 
@@ -750,25 +768,31 @@ static void net_tx_action(unsigned long 
                        DPRINTK("txreq.offset: %x, size: %u, end: %lu\n", 
                                txreq.offset, txreq.size, 
                                (txreq.offset &~PAGE_MASK) + txreq.size);
-                       netbk_tx_err(netif, i);
+                       netbk_tx_err(netif, &txreq, i);
                        continue;
                }
 
                pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
 
                data_len = (txreq.size > PKT_PROT_LEN &&
-                           ret < MAX_SKB_FRAGS + 1) ?
+                           ret < MAX_SKB_FRAGS) ?
                        PKT_PROT_LEN : txreq.size;
 
                skb = alloc_skb(data_len+16, GFP_ATOMIC);
                if (unlikely(skb == NULL)) {
                        DPRINTK("Can't allocate a skb in start_xmit.\n");
-                       netbk_tx_err(netif, i);
+                       netbk_tx_err(netif, &txreq, i);
                        break;
                }
 
                /* Packets passed to netif_rx() must have some headroom. */
                skb_reserve(skb, 16);
+
+               if (txreq.flags & NETTXF_gso) {
+                       skb_shinfo(skb)->gso_size = txtra.gso_size;
+                       skb_shinfo(skb)->gso_segs = txtra.gso_segs;
+                       skb_shinfo(skb)->gso_type = txtra.gso_type;
+               }
 
                gnttab_set_map_op(mop, MMAP_VADDR(pending_idx),
                                  GNTMAP_host_map | GNTMAP_readonly,
@@ -782,7 +806,7 @@ static void net_tx_action(unsigned long 
 
                __skb_put(skb, data_len);
 
-               skb_shinfo(skb)->nr_frags = ret - 1;
+               skb_shinfo(skb)->nr_frags = ret;
                if (data_len < txreq.size) {
                        skb_shinfo(skb)->nr_frags++;
                        skb_shinfo(skb)->frags[0].page =
@@ -898,7 +922,7 @@ irqreturn_t netif_be_int(int irq, void *
 }
 
 static void make_tx_response(netif_t *netif, 
-                            u16      id,
+                            netif_tx_request_t *txp,
                             s8       st)
 {
        RING_IDX i = netif->tx.rsp_prod_pvt;
@@ -906,8 +930,11 @@ static void make_tx_response(netif_t *ne
        int notify;
 
        resp = RING_GET_RESPONSE(&netif->tx, i);
-       resp->id     = id;
+       resp->id     = txp->id;
        resp->status = st;
+
+       if (txp->flags & NETTXF_extra_info)
+               RING_GET_RESPONSE(&netif->tx, ++i)->status = NETIF_RSP_NULL;
 
        netif->tx.rsp_prod_pvt = ++i;
        RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->tx, notify);
diff -r c88ee5ecc39c -r f6d1f558bf1c 
linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c
--- a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c Tue Jun 27 21:30:08 
2006 +1000
+++ b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c Tue Jun 27 21:30:11 
2006 +1000
@@ -101,6 +101,12 @@ static int netback_probe(struct xenbus_d
                        goto abort_transaction;
                }
 
+               err = xenbus_printf(xbt, dev->nodename, "feature-tso", "%d", 1);
+               if (err) {
+                       message = "writing feature-tso";
+                       goto abort_transaction;
+               }
+
                err = xenbus_transaction_end(xbt, 0);
        } while (err == -EAGAIN);
 
diff -r c88ee5ecc39c -r f6d1f558bf1c xen/include/public/io/netif.h
--- a/xen/include/public/io/netif.h     Tue Jun 27 21:30:08 2006 +1000
+++ b/xen/include/public/io/netif.h     Tue Jun 27 21:30:11 2006 +1000
@@ -31,6 +31,13 @@
 #define _NETTXF_more_data      (2)
 #define  NETTXF_more_data      (1U<<_NETTXF_more_data)
 
+/* Packet has GSO fields. */
+#define _NETTXF_gso           (3)
+#define  NETTXF_gso           (1U<<_NETTXF_gso)
+
+/* Packet to be folloed by extra descritptor. */
+#define  NETTXF_extra_info     (NETTXF_gso)
+
 struct netif_tx_request {
     grant_ref_t gref;      /* Reference to buffer page */
     uint16_t offset;       /* Offset within buffer page */
@@ -39,6 +46,13 @@ struct netif_tx_request {
     uint16_t size;         /* Packet size in bytes.       */
 };
 typedef struct netif_tx_request netif_tx_request_t;
+
+/* This structure needs to fit within netif_tx_request for compatibility. */
+struct netif_tx_extra {
+    uint16_t gso_size;    /* GSO MSS. */
+    uint16_t gso_segs;    /* GSO segment count. */
+    uint16_t gso_type;    /* GSO type. */
+};
 
 struct netif_tx_response {
     uint16_t id;
@@ -78,6 +92,7 @@ DEFINE_RING_TYPES(netif_rx, struct netif
 #define NETIF_RSP_DROPPED         -2
 #define NETIF_RSP_ERROR           -1
 #define NETIF_RSP_OKAY             0
+#define NETIF_RSP_NULL            1
 
 #endif
 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.