ia64/xen-unstable

changeset 9567:4ad317429111

Make checksum handling in the virtual network drivers more robust.
Largely this involves making the logic symmetrical: for example,
not only should netfront be able to tell netback that a packet has
an empty protocol checksum field, but the reverse must also be true.

Another change is that the drivers only advertise IP checksum
offload functionality. There is currently no information
propagated across the device channel about the offset of the
protocol-specific checksum field. Therefore it is not safe to
defer checksum calculation for protocols the remote end may not
understand -- it will end up dropping having to drop the packet.

Yet another change is to allow netback to disable tx checksum
offload, just as we already could for netfront. Currently there is
no support for disabling rx checksum offload -- that would seem
to require some way of propagating the checksum-offload advertisement
(or lack of it) across the device channel, as it really ought to be
the transmitter that acts on it.

Thanks to Ian Jackson for pointing out some of the problems with
our checksum-offload handling. Several of the changes here are
due to his comments.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Sun Apr 02 16:16:53 2006 +0100 (2006-04-02)
parents 99b2e765d643
children d0d3fef37685
files linux-2.6-xen-sparse/drivers/xen/netback/interface.c linux-2.6-xen-sparse/drivers/xen/netback/loopback.c linux-2.6-xen-sparse/drivers/xen/netback/netback.c linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c linux-2.6-xen-sparse/include/linux/skbuff.h linux-2.6-xen-sparse/net/core/dev.c linux-2.6-xen-sparse/net/core/skbuff.c
line diff
     1.1 --- a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c	Sun Apr 02 09:49:17 2006 +0100
     1.2 +++ b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c	Sun Apr 02 16:16:53 2006 +0100
     1.3 @@ -31,6 +31,7 @@
     1.4   */
     1.5  
     1.6  #include "common.h"
     1.7 +#include <linux/ethtool.h>
     1.8  #include <linux/rtnetlink.h>
     1.9  
    1.10  static void __netif_up(netif_t *netif)
    1.11 @@ -71,6 +72,12 @@ static int net_close(struct net_device *
    1.12  	return 0;
    1.13  }
    1.14  
    1.15 +static struct ethtool_ops network_ethtool_ops =
    1.16 +{
    1.17 +	.get_tx_csum = ethtool_op_get_tx_csum,
    1.18 +	.set_tx_csum = ethtool_op_set_tx_csum,
    1.19 +};
    1.20 +
    1.21  netif_t *alloc_netif(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN])
    1.22  {
    1.23  	int err = 0, i;
    1.24 @@ -101,7 +108,9 @@ netif_t *alloc_netif(domid_t domid, unsi
    1.25  	dev->get_stats       = netif_be_get_stats;
    1.26  	dev->open            = net_open;
    1.27  	dev->stop            = net_close;
    1.28 -	dev->features        = NETIF_F_NO_CSUM;
    1.29 +	dev->features        = NETIF_F_IP_CSUM;
    1.30 +
    1.31 +	SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
    1.32  
    1.33  	/* Disable queuing. */
    1.34  	dev->tx_queue_len = 0;
     2.1 --- a/linux-2.6-xen-sparse/drivers/xen/netback/loopback.c	Sun Apr 02 09:49:17 2006 +0100
     2.2 +++ b/linux-2.6-xen-sparse/drivers/xen/netback/loopback.c	Sun Apr 02 16:16:53 2006 +0100
     2.3 @@ -100,10 +100,10 @@ static int loopback_start_xmit(struct sk
     2.4  		/* Defer checksum calculation. */
     2.5  		skb->proto_csum_blank = 1;
     2.6  		/* Must be a local packet: assert its integrity. */
     2.7 -		skb->proto_csum_valid = 1;
     2.8 +		skb->proto_data_valid = 1;
     2.9  	}
    2.10  
    2.11 -	skb->ip_summed = skb->proto_csum_valid ?
    2.12 +	skb->ip_summed = skb->proto_data_valid ?
    2.13  		CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
    2.14  
    2.15  	skb->pkt_type = PACKET_HOST; /* overridden by eth_type_trans() */
    2.16 @@ -121,6 +121,12 @@ static struct net_device_stats *loopback
    2.17  	return &np->stats;
    2.18  }
    2.19  
    2.20 +static struct ethtool_ops network_ethtool_ops =
    2.21 +{
    2.22 +	.get_tx_csum = ethtool_op_get_tx_csum,
    2.23 +	.set_tx_csum = ethtool_op_set_tx_csum,
    2.24 +};
    2.25 +
    2.26  static void loopback_construct(struct net_device *dev, struct net_device *lo)
    2.27  {
    2.28  	struct net_private *np = netdev_priv(dev);
    2.29 @@ -134,7 +140,11 @@ static void loopback_construct(struct ne
    2.30  
    2.31  	dev->tx_queue_len    = 0;
    2.32  
    2.33 -	dev->features        = NETIF_F_HIGHDMA | NETIF_F_LLTX;
    2.34 +	dev->features        = (NETIF_F_HIGHDMA |
    2.35 +				NETIF_F_LLTX |
    2.36 +				NETIF_F_IP_CSUM);
    2.37 +
    2.38 +	SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
    2.39  
    2.40  	/*
    2.41  	 * We do not set a jumbo MTU on the interface. Otherwise the network
    2.42 @@ -147,12 +157,6 @@ static void loopback_construct(struct ne
    2.43  	/*dev->mtu             = 16*1024;*/
    2.44  }
    2.45  
    2.46 -static struct ethtool_ops network_ethtool_ops =
    2.47 -{
    2.48 -	.get_tx_csum = ethtool_op_get_tx_csum,
    2.49 -	.set_tx_csum = ethtool_op_set_tx_csum,
    2.50 -};
    2.51 -
    2.52  static int __init make_loopback(int i)
    2.53  {
    2.54  	struct net_device *dev1, *dev2;
    2.55 @@ -172,11 +176,6 @@ static int __init make_loopback(int i)
    2.56  	loopback_construct(dev1, dev2);
    2.57  	loopback_construct(dev2, dev1);
    2.58  
    2.59 -	dev1->features |= NETIF_F_NO_CSUM;
    2.60 -	dev2->features |= NETIF_F_IP_CSUM;
    2.61 -
    2.62 -	SET_ETHTOOL_OPS(dev2, &network_ethtool_ops);
    2.63 -
    2.64  	/*
    2.65  	 * Initialise a dummy MAC address for the 'dummy backend' interface. We
    2.66  	 * choose the numerically largest non-broadcast address to prevent the
     3.1 --- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c	Sun Apr 02 09:49:17 2006 +0100
     3.2 +++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c	Sun Apr 02 16:16:53 2006 +0100
     3.3 @@ -171,7 +171,7 @@ int netif_be_start_xmit(struct sk_buff *
     3.4  				     skb->len + hlen);
     3.5  		BUG_ON(ret);
     3.6  		nskb->dev = skb->dev;
     3.7 -		nskb->proto_csum_valid = skb->proto_csum_valid;
     3.8 +		nskb->proto_data_valid = skb->proto_data_valid;
     3.9  		dev_kfree_skb(skb);
    3.10  		skb = nskb;
    3.11  	}
    3.12 @@ -213,7 +213,7 @@ static void net_rx_action(unsigned long 
    3.13  {
    3.14  	netif_t *netif = NULL; 
    3.15  	s8 status;
    3.16 -	u16 size, id, irq;
    3.17 +	u16 size, id, irq, flags;
    3.18  	multicall_entry_t *mcl;
    3.19  	mmu_update_t *mmu;
    3.20  	gnttab_transfer_t *gop;
    3.21 @@ -328,10 +328,14 @@ static void net_rx_action(unsigned long 
    3.22  		}
    3.23  		irq = netif->irq;
    3.24  		id = RING_GET_REQUEST(&netif->rx, netif->rx.rsp_prod_pvt)->id;
    3.25 +		flags = 0;
    3.26 +		if (skb->ip_summed == CHECKSUM_HW)
    3.27 +			flags |= NETRXF_csum_blank;
    3.28 +		if (skb->proto_data_valid)
    3.29 +			flags |= NETRXF_data_validated;
    3.30  		if (make_rx_response(netif, id, status,
    3.31  				     (unsigned long)skb->data & ~PAGE_MASK,
    3.32 -				     size, skb->proto_csum_valid ?
    3.33 -				     NETRXF_data_validated : 0) &&
    3.34 +				     size, flags) &&
    3.35  		    (rx_notify[irq] == 0)) {
    3.36  			rx_notify[irq] = 1;
    3.37  			notify_list[notify_nr++] = irq;
    3.38 @@ -654,12 +658,13 @@ static void net_tx_action(unsigned long 
    3.39  		skb->dev      = netif->dev;
    3.40  		skb->protocol = eth_type_trans(skb, skb->dev);
    3.41  
    3.42 -		/*
    3.43 -                 * No checking needed on localhost, but remember the field is
    3.44 -                 * blank. 
    3.45 -                 */
    3.46 -		skb->ip_summed        = CHECKSUM_UNNECESSARY;
    3.47 -		skb->proto_csum_valid = 1;
    3.48 +		if (txreq.flags & NETTXF_data_validated) {
    3.49 +			skb->ip_summed = CHECKSUM_UNNECESSARY;
    3.50 +			skb->proto_data_valid = 1;
    3.51 +		} else {
    3.52 +			skb->ip_summed = CHECKSUM_NONE;
    3.53 +			skb->proto_data_valid = 0;
    3.54 +		}
    3.55  		skb->proto_csum_blank = !!(txreq.flags & NETTXF_csum_blank);
    3.56  
    3.57  		netif->stats.rx_bytes += txreq.size;
     4.1 --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c	Sun Apr 02 09:49:17 2006 +0100
     4.2 +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c	Sun Apr 02 16:16:53 2006 +0100
     4.3 @@ -696,7 +696,12 @@ static int network_start_xmit(struct sk_
     4.4  	tx->gref = np->grant_tx_ref[id] = ref;
     4.5  	tx->offset = (unsigned long)skb->data & ~PAGE_MASK;
     4.6  	tx->size = skb->len;
     4.7 -	tx->flags = (skb->ip_summed == CHECKSUM_HW) ? NETTXF_csum_blank : 0;
     4.8 +
     4.9 +	tx->flags = 0;
    4.10 +	if (skb->ip_summed == CHECKSUM_HW)
    4.11 +		tx->flags |= NETTXF_csum_blank;
    4.12 +	if (skb->proto_data_valid)
    4.13 +		tx->flags |= NETTXF_data_validated;
    4.14  
    4.15  	np->tx.req_prod_pvt = i + 1;
    4.16  	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->tx, notify);
    4.17 @@ -811,8 +816,14 @@ static int netif_poll(struct net_device 
    4.18  		skb->len  = rx->status;
    4.19  		skb->tail = skb->data + skb->len;
    4.20  
    4.21 -		if (rx->flags & NETRXF_data_validated)
    4.22 +		if (rx->flags & NETRXF_data_validated) {
    4.23  			skb->ip_summed = CHECKSUM_UNNECESSARY;
    4.24 +			skb->proto_data_valid = 1;
    4.25 +		} else {
    4.26 +			skb->ip_summed = CHECKSUM_NONE;
    4.27 +			skb->proto_data_valid = 0;
    4.28 +		}
    4.29 +		skb->proto_csum_blank = !!(rx->flags & NETRXF_csum_blank);
    4.30  
    4.31  		np->stats.rx_packets++;
    4.32  		np->stats.rx_bytes += rx->status;
     5.1 --- a/linux-2.6-xen-sparse/include/linux/skbuff.h	Sun Apr 02 09:49:17 2006 +0100
     5.2 +++ b/linux-2.6-xen-sparse/include/linux/skbuff.h	Sun Apr 02 16:16:53 2006 +0100
     5.3 @@ -189,7 +189,7 @@ enum {
     5.4   *	@local_df: allow local fragmentation
     5.5   *	@cloned: Head may be cloned (check refcnt to be sure)
     5.6   *	@nohdr: Payload reference only, must not modify header
     5.7 - *	@proto_csum_valid: Protocol csum validated since arriving at localhost
     5.8 + *	@proto_data_valid: Protocol data validated since arriving at localhost
     5.9   *	@proto_csum_blank: Protocol csum must be added before leaving localhost
    5.10   *	@pkt_type: Packet class
    5.11   *	@fclone: skbuff clone status
    5.12 @@ -271,7 +271,7 @@ struct sk_buff {
    5.13  				ipvs_property:1;
    5.14  #else
    5.15  				ipvs_property:1,
    5.16 -				proto_csum_valid:1,
    5.17 +				proto_data_valid:1,
    5.18  				proto_csum_blank:1;
    5.19  #endif
    5.20  	__be16			protocol;
     6.1 --- a/linux-2.6-xen-sparse/net/core/dev.c	Sun Apr 02 09:49:17 2006 +0100
     6.2 +++ b/linux-2.6-xen-sparse/net/core/dev.c	Sun Apr 02 16:16:53 2006 +0100
     6.3 @@ -1649,12 +1649,12 @@ int netif_receive_skb(struct sk_buff *sk
     6.4  #ifdef CONFIG_XEN
     6.5  	switch (skb->ip_summed) {
     6.6  	case CHECKSUM_UNNECESSARY:
     6.7 -		skb->proto_csum_valid = 1;
     6.8 +		skb->proto_data_valid = 1;
     6.9  		break;
    6.10  	case CHECKSUM_HW:
    6.11  		/* XXX Implement me. */
    6.12  	default:
    6.13 -		skb->proto_csum_valid = 0;
    6.14 +		skb->proto_data_valid = 0;
    6.15  		break;
    6.16  	}
    6.17  #endif
     7.1 --- a/linux-2.6-xen-sparse/net/core/skbuff.c	Sun Apr 02 09:49:17 2006 +0100
     7.2 +++ b/linux-2.6-xen-sparse/net/core/skbuff.c	Sun Apr 02 16:16:53 2006 +0100
     7.3 @@ -428,7 +428,7 @@ struct sk_buff *skb_clone(struct sk_buff
     7.4  	n->cloned = 1;
     7.5  	n->nohdr = 0;
     7.6  #ifdef CONFIG_XEN
     7.7 -	C(proto_csum_valid);
     7.8 +	C(proto_data_valid);
     7.9  	C(proto_csum_blank);
    7.10  #endif
    7.11  	C(pkt_type);