ia64/xen-unstable

changeset 10883:485616ab73e3

[NET] front: Add TSO support

This patch adds TCP Segmentation Offload (TSO) support to the
frontend.
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@gondor.apana.org.au>

Disable for now, as in domU->dom0 direction.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Mon Jul 31 17:45:22 2006 +0100 (2006-07-31)
parents 9f29252c23b6
children 637fa5352fad
files linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c xen/include/public/io/netif.h
line diff
     1.1 --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c	Mon Jul 31 17:42:13 2006 +0100
     1.2 +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c	Mon Jul 31 17:45:22 2006 +0100
     1.3 @@ -116,6 +116,11 @@ struct netfront_info {
     1.4  	struct mmu_update rx_mmu[NET_RX_RING_SIZE];
     1.5  };
     1.6  
     1.7 +struct netfront_rx_info {
     1.8 +	struct netif_rx_response rx;
     1.9 +	struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
    1.10 +};
    1.11 +
    1.12  /*
    1.13   * Access macros for acquiring freeing slots in tx_skbs[].
    1.14   */
    1.15 @@ -333,6 +338,14 @@ again:
    1.16  		goto abort_transaction;
    1.17  	}
    1.18  
    1.19 +#if 0 /* KAF: After the protocol is finalised. */
    1.20 +	err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1);
    1.21 +	if (err) {
    1.22 +		message = "writing feature-gso-tcpv4";
    1.23 +		goto abort_transaction;
    1.24 +	}
    1.25 +#endif
    1.26 +
    1.27  	err = xenbus_transaction_end(xbt, 0);
    1.28  	if (err) {
    1.29  		if (err == -EAGAIN)
    1.30 @@ -899,12 +912,54 @@ static void xennet_move_rx_slot(struct n
    1.31  	np->rx.req_prod_pvt++;
    1.32  }
    1.33  
    1.34 +int xennet_get_extras(struct netfront_info *np,
    1.35 +		      struct netif_extra_info *extras, RING_IDX rp)
    1.36 +
    1.37 +{
    1.38 +	struct netif_extra_info *extra;
    1.39 +	RING_IDX cons = np->rx.rsp_cons;
    1.40 +	int err = 0;
    1.41 +
    1.42 +	do {
    1.43 +		struct sk_buff *skb;
    1.44 +		grant_ref_t ref;
    1.45 +
    1.46 +		if (unlikely(cons + 1 == rp)) {
    1.47 +			if (net_ratelimit())
    1.48 +				WPRINTK("Missing extra info\n");
    1.49 +			err = -EBADR;
    1.50 +			break;
    1.51 +		}
    1.52 +
    1.53 +		extra = (struct netif_extra_info *)
    1.54 +			RING_GET_RESPONSE(&np->rx, ++cons);
    1.55 +
    1.56 +		if (unlikely(!extra->type ||
    1.57 +			     extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
    1.58 +			if (net_ratelimit())
    1.59 +				WPRINTK("Invalid extra type: %d\n",
    1.60 +					extra->type);
    1.61 +			err = -EINVAL;
    1.62 +		} else
    1.63 +			memcpy(&extras[extra->type - 1], extra, sizeof(*extra));
    1.64 +
    1.65 +		skb = xennet_get_rx_skb(np, cons);
    1.66 +		ref = xennet_get_rx_ref(np, cons);
    1.67 +		xennet_move_rx_slot(np, skb, ref);
    1.68 +	} while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE);
    1.69 +
    1.70 +	np->rx.rsp_cons = cons;
    1.71 +	return err;
    1.72 +}
    1.73 +
    1.74  static int xennet_get_responses(struct netfront_info *np,
    1.75 -				struct netif_rx_response *rx, RING_IDX rp,
    1.76 +				struct netfront_rx_info *rinfo, RING_IDX rp,
    1.77  				struct sk_buff_head *list, int count)
    1.78  {
    1.79  	struct mmu_update *mmu = np->rx_mmu + count;
    1.80  	struct multicall_entry *mcl = np->rx_mcl + count;
    1.81 +	struct netif_rx_response *rx = &rinfo->rx;
    1.82 +	struct netif_extra_info *extras = rinfo->extras;
    1.83  	RING_IDX cons = np->rx.rsp_cons;
    1.84  	struct sk_buff *skb = xennet_get_rx_skb(np, cons);
    1.85  	grant_ref_t ref = xennet_get_rx_ref(np, cons);
    1.86 @@ -912,6 +967,11 @@ static int xennet_get_responses(struct n
    1.87  	int frags = 1;
    1.88  	int err = 0;
    1.89  
    1.90 +	if (rx->flags & NETRXF_extra_info) {
    1.91 +		err = xennet_get_extras(np, extras, rp);
    1.92 +		cons = np->rx.rsp_cons;
    1.93 +	}
    1.94 +
    1.95  	for (;;) {
    1.96  		unsigned long mfn;
    1.97  
    1.98 @@ -1023,11 +1083,38 @@ static RING_IDX xennet_fill_frags(struct
    1.99  	return cons;
   1.100  }
   1.101  
   1.102 +static int xennet_set_skb_gso(struct sk_buff *skb, struct netif_extra_info *gso)
   1.103 +{
   1.104 +	if (!gso->u.gso.size) {
   1.105 +		if (net_ratelimit())
   1.106 +			WPRINTK("GSO size must not be zero.\n");
   1.107 +		return -EINVAL;
   1.108 +	}
   1.109 +
   1.110 +	/* Currently only TCPv4 S.O. is supported. */
   1.111 +	if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
   1.112 +		if (net_ratelimit())
   1.113 +			WPRINTK("Bad GSO type %d.\n", gso->u.gso.type);
   1.114 +		return -EINVAL;
   1.115 +	}
   1.116 +
   1.117 +	skb_shinfo(skb)->gso_size = gso->u.gso.size;
   1.118 +	skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
   1.119 +
   1.120 +	/* Header must be checked, and gso_segs computed. */
   1.121 +	skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
   1.122 +	skb_shinfo(skb)->gso_segs = 0;
   1.123 +
   1.124 +	return 0;
   1.125 +}
   1.126 +
   1.127  static int netif_poll(struct net_device *dev, int *pbudget)
   1.128  {
   1.129  	struct netfront_info *np = netdev_priv(dev);
   1.130  	struct sk_buff *skb;
   1.131 -	struct netif_rx_response *rx;
   1.132 +	struct netfront_rx_info rinfo;
   1.133 +	struct netif_rx_response *rx = &rinfo.rx;
   1.134 +	struct netif_extra_info *extras = rinfo.extras;
   1.135  	RING_IDX i, rp;
   1.136  	struct multicall_entry *mcl;
   1.137  	int work_done, budget, more_to_do = 1;
   1.138 @@ -1058,12 +1145,14 @@ static int netif_poll(struct net_device 
   1.139  	for (i = np->rx.rsp_cons, work_done = 0, pages_done = 0;
   1.140  	     (i != rp) && (work_done < budget);
   1.141  	     np->rx.rsp_cons = ++i, work_done++) {
   1.142 -		rx = RING_GET_RESPONSE(&np->rx, i);
   1.143 +		memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx));
   1.144 +		memset(extras, 0, sizeof(extras));
   1.145  
   1.146 -		err = xennet_get_responses(np, rx, rp, &tmpq, pages_done);
   1.147 +		err = xennet_get_responses(np, &rinfo, rp, &tmpq, pages_done);
   1.148  		pages_done += skb_queue_len(&tmpq);
   1.149  
   1.150  		if (unlikely(err)) {
   1.151 +err:
   1.152  			i = np->rx.rsp_cons + skb_queue_len(&tmpq) - 1;
   1.153  			work_done--;
   1.154  			while ((skb = __skb_dequeue(&tmpq)))
   1.155 @@ -1074,6 +1163,16 @@ static int netif_poll(struct net_device 
   1.156  
   1.157  		skb = __skb_dequeue(&tmpq);
   1.158  
   1.159 +		if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
   1.160 +			struct netif_extra_info *gso;
   1.161 +			gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
   1.162 +
   1.163 +			if (unlikely(xennet_set_skb_gso(skb, gso))) {
   1.164 +				__skb_queue_head(&tmpq, skb);
   1.165 +				goto err;
   1.166 +			}
   1.167 +		}
   1.168 +
   1.169  		skb->nh.raw = (void *)skb_shinfo(skb)->frags[0].page;
   1.170  		skb->h.raw = skb->nh.raw + rx->offset;
   1.171  
     2.1 --- a/xen/include/public/io/netif.h	Mon Jul 31 17:42:13 2006 +0100
     2.2 +++ b/xen/include/public/io/netif.h	Mon Jul 31 17:45:22 2006 +0100
     2.3 @@ -128,6 +128,10 @@ typedef struct netif_rx_request netif_rx
     2.4  #define _NETRXF_more_data      (2)
     2.5  #define  NETRXF_more_data      (1U<<_NETRXF_more_data)
     2.6  
     2.7 +/* Packet to be followed by extra descriptor(s). */
     2.8 +#define _NETRXF_extra_info     (3)
     2.9 +#define  NETRXF_extra_info     (1U<<_NETRXF_extra_info)
    2.10 +
    2.11  struct netif_rx_response {
    2.12      uint16_t id;
    2.13      uint16_t offset;       /* Offset in page of start of received packet  */