ia64/xen-unstable

changeset 10714:a4041ac6f152

[NET] net-gso.patch: Fix up GSO packets with broken checksums

Here is the original changelog:

[NET] gso: Fix up GSO packets with broken checksums

Certain subsystems in the stack (e.g., netfilter) can break the
partial
checksum on GSO packets. Until they're fixed, this patch allows
this to
work by recomputing the partial checksums through the GSO
mechanism.

Once they've all been converted to update the partial checksum
instead of
clearing it, this workaround can be removed.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
author kfraser@localhost.localdomain
date Mon Jul 10 15:36:04 2006 +0100 (2006-07-10)
parents 09b8041dc2fd
children 5014fd2b5c5a
files linux-2.6-xen-sparse/include/linux/skbuff.h linux-2.6-xen-sparse/net/core/dev.c patches/linux-2.6.16.13/net-gso.patch
line diff
     1.1 --- a/linux-2.6-xen-sparse/include/linux/skbuff.h	Mon Jul 10 15:23:15 2006 +0100
     1.2 +++ b/linux-2.6-xen-sparse/include/linux/skbuff.h	Mon Jul 10 15:36:04 2006 +0100
     1.3 @@ -1412,5 +1412,10 @@ static inline void nf_bridge_get(struct 
     1.4  static inline void nf_reset(struct sk_buff *skb) {}
     1.5  #endif /* CONFIG_NETFILTER */
     1.6  
     1.7 +static inline int skb_is_gso(const struct sk_buff *skb)
     1.8 +{
     1.9 +	return skb_shinfo(skb)->gso_size;
    1.10 +}
    1.11 +
    1.12  #endif	/* __KERNEL__ */
    1.13  #endif	/* _LINUX_SKBUFF_H */
     2.1 --- a/linux-2.6-xen-sparse/net/core/dev.c	Mon Jul 10 15:23:15 2006 +0100
     2.2 +++ b/linux-2.6-xen-sparse/net/core/dev.c	Mon Jul 10 15:36:04 2006 +0100
     2.3 @@ -1089,9 +1089,17 @@ int skb_checksum_help(struct sk_buff *sk
     2.4  	unsigned int csum;
     2.5  	int ret = 0, offset = skb->h.raw - skb->data;
     2.6  
     2.7 -	if (inward) {
     2.8 -		skb->ip_summed = CHECKSUM_NONE;
     2.9 -		goto out;
    2.10 +	if (inward)
    2.11 +		goto out_set_summed;
    2.12 +
    2.13 +	if (unlikely(skb_shinfo(skb)->gso_size)) {
    2.14 +		static int warned;
    2.15 +
    2.16 +		WARN_ON(!warned);
    2.17 +		warned = 1;
    2.18 +
    2.19 +		/* Let GSO fix up the checksum. */
    2.20 +		goto out_set_summed;
    2.21  	}
    2.22  
    2.23  	if (skb_cloned(skb)) {
    2.24 @@ -1108,6 +1116,8 @@ int skb_checksum_help(struct sk_buff *sk
    2.25  	BUG_ON(skb->csum + 2 > offset);
    2.26  
    2.27  	*(u16*)(skb->h.raw + skb->csum) = csum_fold(csum);
    2.28 +
    2.29 +out_set_summed:
    2.30  	skb->ip_summed = CHECKSUM_NONE;
    2.31  out:	
    2.32  	return ret;
    2.33 @@ -1128,17 +1138,35 @@ struct sk_buff *skb_gso_segment(struct s
    2.34  	struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
    2.35  	struct packet_type *ptype;
    2.36  	int type = skb->protocol;
    2.37 +	int err;
    2.38  
    2.39  	BUG_ON(skb_shinfo(skb)->frag_list);
    2.40 -	BUG_ON(skb->ip_summed != CHECKSUM_HW);
    2.41  
    2.42  	skb->mac.raw = skb->data;
    2.43  	skb->mac_len = skb->nh.raw - skb->data;
    2.44  	__skb_pull(skb, skb->mac_len);
    2.45  
    2.46 +	if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
    2.47 +		static int warned;
    2.48 +
    2.49 +		WARN_ON(!warned);
    2.50 +		warned = 1;
    2.51 +
    2.52 +		if (skb_header_cloned(skb) &&
    2.53 +		    (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
    2.54 +			return ERR_PTR(err);
    2.55 +	}
    2.56 +
    2.57  	rcu_read_lock();
    2.58  	list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) {
    2.59  		if (ptype->type == type && !ptype->dev && ptype->gso_segment) {
    2.60 +			if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
    2.61 +				err = ptype->gso_send_check(skb);
    2.62 +				segs = ERR_PTR(err);
    2.63 +				if (err || skb_gso_ok(skb, features))
    2.64 +					break;
    2.65 +				__skb_push(skb, skb->data - skb->nh.raw);
    2.66 +			}
    2.67  			segs = ptype->gso_segment(skb, features);
    2.68  			break;
    2.69  		}
     3.1 --- a/patches/linux-2.6.16.13/net-gso.patch	Mon Jul 10 15:23:15 2006 +0100
     3.2 +++ b/patches/linux-2.6.16.13/net-gso.patch	Mon Jul 10 15:36:04 2006 +0100
     3.3 @@ -104,7 +104,7 @@ index dd41049..6615583 100644
     3.4   	if (skb_shinfo(skb)->nr_frags == 0) {
     3.5   		struct cp_desc *txd = &cp->tx_ring[entry];
     3.6  diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
     3.7 -index a24200d..b5e39a1 100644
     3.8 +index a24200d..29d9218 100644
     3.9  --- a/drivers/net/bnx2.c
    3.10  +++ b/drivers/net/bnx2.c
    3.11  @@ -1593,7 +1593,7 @@ bnx2_tx_int(struct bnx2 *bp)
    3.12 @@ -112,7 +112,7 @@ index a24200d..b5e39a1 100644
    3.13   #ifdef BCM_TSO 
    3.14   		/* partial BD completions possible with TSO packets */
    3.15  -		if (skb_shinfo(skb)->tso_size) {
    3.16 -+		if (skb_shinfo(skb)->gso_size) {
    3.17 ++		if (skb_is_gso(skb)) {
    3.18   			u16 last_idx, last_ring_idx;
    3.19   
    3.20   			last_idx = sw_cons +
    3.21 @@ -178,7 +178,7 @@ index bcf9f17..e970921 100644
    3.22   	bond_dev->features |= NETIF_F_LLTX;
    3.23   
    3.24  diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
    3.25 -index 30ff8ea..7b7d360 100644
    3.26 +index 30ff8ea..7d72e16 100644
    3.27  --- a/drivers/net/chelsio/sge.c
    3.28  +++ b/drivers/net/chelsio/sge.c
    3.29  @@ -1419,7 +1419,7 @@ int t1_start_xmit(struct sk_buff *skb, s
    3.30 @@ -186,7 +186,7 @@ index 30ff8ea..7b7d360 100644
    3.31   
    3.32   #ifdef NETIF_F_TSO
    3.33  -	if (skb_shinfo(skb)->tso_size) {
    3.34 -+	if (skb_shinfo(skb)->gso_size) {
    3.35 ++	if (skb_is_gso(skb)) {
    3.36   		int eth_type;
    3.37   		struct cpl_tx_pkt_lso *hdr;
    3.38   
    3.39 @@ -200,7 +200,7 @@ index 30ff8ea..7b7d360 100644
    3.40   		cpl = (struct cpl_tx_pkt *)hdr;
    3.41   		sge->stats.tx_lso_pkts++;
    3.42  diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
    3.43 -index fa29402..681d284 100644
    3.44 +index fa29402..96ddc24 100644
    3.45  --- a/drivers/net/e1000/e1000_main.c
    3.46  +++ b/drivers/net/e1000/e1000_main.c
    3.47  @@ -2526,7 +2526,7 @@ #ifdef NETIF_F_TSO
    3.48 @@ -208,7 +208,7 @@ index fa29402..681d284 100644
    3.49   	int err;
    3.50   
    3.51  -	if (skb_shinfo(skb)->tso_size) {
    3.52 -+	if (skb_shinfo(skb)->gso_size) {
    3.53 ++	if (skb_is_gso(skb)) {
    3.54   		if (skb_header_cloned(skb)) {
    3.55   			err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
    3.56   			if (err)
    3.57 @@ -226,7 +226,7 @@ index fa29402..681d284 100644
    3.58   		 * DMAd to the controller */
    3.59   		if (!skb->data_len && tx_ring->last_tx_tso &&
    3.60  -				!skb_shinfo(skb)->tso_size) {
    3.61 -+				!skb_shinfo(skb)->gso_size) {
    3.62 ++		    !skb_is_gso(skb)) {
    3.63   			tx_ring->last_tx_tso = 0;
    3.64   			size -= 4;
    3.65   		}
    3.66 @@ -239,17 +239,18 @@ index fa29402..681d284 100644
    3.67   	/* The controller does a simple calculation to 
    3.68   	 * make sure there is enough room in the FIFO before
    3.69   	 * initiating the DMA for each buffer.  The calc is:
    3.70 -@@ -2935,7 +2935,7 @@ #endif
    3.71 +@@ -2934,8 +2934,7 @@ #endif
    3.72 + 
    3.73   #ifdef NETIF_F_TSO
    3.74   	/* Controller Erratum workaround */
    3.75 - 	if (!skb->data_len && tx_ring->last_tx_tso &&
    3.76 +-	if (!skb->data_len && tx_ring->last_tx_tso &&
    3.77  -		!skb_shinfo(skb)->tso_size)
    3.78 -+		!skb_shinfo(skb)->gso_size)
    3.79 ++	if (!skb->data_len && tx_ring->last_tx_tso && !skb_is_gso(skb))
    3.80   		count++;
    3.81   #endif
    3.82   
    3.83  diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
    3.84 -index 3682ec6..c35f16e 100644
    3.85 +index 3682ec6..c6ca459 100644
    3.86  --- a/drivers/net/forcedeth.c
    3.87  +++ b/drivers/net/forcedeth.c
    3.88  @@ -482,9 +482,9 @@ #define LPA_1000HALF	0x0400
    3.89 @@ -279,7 +280,7 @@ index 3682ec6..c35f16e 100644
    3.90   #ifdef NETIF_F_TSO
    3.91  -	if (skb_shinfo(skb)->tso_size)
    3.92  -		tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT);
    3.93 -+	if (skb_shinfo(skb)->gso_size)
    3.94 ++	if (skb_is_gso(skb))
    3.95  +		tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
    3.96   	else
    3.97   #endif
    3.98 @@ -450,7 +451,7 @@ index a9f49f0..339d4a7 100644
    3.99   	}
   3.100   
   3.101  diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
   3.102 -index f9f77e4..bdab369 100644
   3.103 +index f9f77e4..7d187d0 100644
   3.104  --- a/drivers/net/ixgb/ixgb_main.c
   3.105  +++ b/drivers/net/ixgb/ixgb_main.c
   3.106  @@ -1163,7 +1163,7 @@ #ifdef NETIF_F_TSO
   3.107 @@ -458,7 +459,7 @@ index f9f77e4..bdab369 100644
   3.108   	int err;
   3.109   
   3.110  -	if(likely(skb_shinfo(skb)->tso_size)) {
   3.111 -+	if(likely(skb_shinfo(skb)->gso_size)) {
   3.112 ++	if (likely(skb_is_gso(skb))) {
   3.113   		if (skb_header_cloned(skb)) {
   3.114   			err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
   3.115   			if (err)
   3.116 @@ -472,7 +473,7 @@ index f9f77e4..bdab369 100644
   3.117   		skb->nh.iph->check = 0;
   3.118   		skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr,
   3.119  diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
   3.120 -index 690a1aa..9bcaa80 100644
   3.121 +index 690a1aa..3843e0a 100644
   3.122  --- a/drivers/net/loopback.c
   3.123  +++ b/drivers/net/loopback.c
   3.124  @@ -74,7 +74,7 @@ static void emulate_large_send_offload(s
   3.125 @@ -489,7 +490,7 @@ index 690a1aa..9bcaa80 100644
   3.126   
   3.127   #ifdef LOOPBACK_TSO
   3.128  -	if (skb_shinfo(skb)->tso_size) {
   3.129 -+	if (skb_shinfo(skb)->gso_size) {
   3.130 ++	if (skb_is_gso(skb)) {
   3.131   		BUG_ON(skb->protocol != htons(ETH_P_IP));
   3.132   		BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);
   3.133   
   3.134 @@ -600,7 +601,7 @@ index b7f00d6..439f45f 100644
   3.135   	writeq(val64, &tx_fifo->List_Control);
   3.136   
   3.137  diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
   3.138 -index 0618cd5..2a55eb3 100644
   3.139 +index 0618cd5..aa06a82 100644
   3.140  --- a/drivers/net/sky2.c
   3.141  +++ b/drivers/net/sky2.c
   3.142  @@ -1125,7 +1125,7 @@ static unsigned tx_le_req(const struct s
   3.143 @@ -608,7 +609,7 @@ index 0618cd5..2a55eb3 100644
   3.144   	count += skb_shinfo(skb)->nr_frags * count;
   3.145   
   3.146  -	if (skb_shinfo(skb)->tso_size)
   3.147 -+	if (skb_shinfo(skb)->gso_size)
   3.148 ++	if (skb_is_gso(skb))
   3.149   		++count;
   3.150   
   3.151   	if (skb->ip_summed == CHECKSUM_HW)
   3.152 @@ -667,7 +668,7 @@ index 5b1af39..11de5af 100644
   3.153   		np->stats.rx_missed_errors += ioread32(ioaddr + RxMissed) & 0xffff;
   3.154   
   3.155  diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
   3.156 -index 4c76cb7..30c48c9 100644
   3.157 +index 4c76cb7..3d62abc 100644
   3.158  --- a/drivers/net/typhoon.c
   3.159  +++ b/drivers/net/typhoon.c
   3.160  @@ -340,7 +340,7 @@ #define typhoon_synchronize_irq(x) synch
   3.161 @@ -679,6 +680,24 @@ index 4c76cb7..30c48c9 100644
   3.162   #define TSO_NUM_DESCRIPTORS	2
   3.163   #define TSO_OFFLOAD_ON		TYPHOON_OFFLOAD_TCP_SEGMENT
   3.164   #else
   3.165 +@@ -805,7 +805,7 @@ typhoon_start_tx(struct sk_buff *skb, st
   3.166 + 	 * If problems develop with TSO, check this first.
   3.167 + 	 */
   3.168 + 	numDesc = skb_shinfo(skb)->nr_frags + 1;
   3.169 +-	if(skb_tso_size(skb))
   3.170 ++	if (skb_is_gso(skb))
   3.171 + 		numDesc++;
   3.172 + 
   3.173 + 	/* When checking for free space in the ring, we need to also
   3.174 +@@ -845,7 +845,7 @@ typhoon_start_tx(struct sk_buff *skb, st
   3.175 + 				TYPHOON_TX_PF_VLAN_TAG_SHIFT);
   3.176 + 	}
   3.177 + 
   3.178 +-	if(skb_tso_size(skb)) {
   3.179 ++	if (skb_is_gso(skb)) {
   3.180 + 		first_txd->processFlags |= TYPHOON_TX_PF_TCP_SEGMENT;
   3.181 + 		first_txd->numDesc++;
   3.182 + 
   3.183  diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
   3.184  index ed1f837..2eb6b5f 100644
   3.185  --- a/drivers/net/via-velocity.c
   3.186 @@ -769,7 +788,7 @@ index 82cb4af..57cec40 100644
   3.187   
   3.188   static inline struct qeth_eddp_context *
   3.189  diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
   3.190 -index dba7f7f..d9cc997 100644
   3.191 +index dba7f7f..a3ea8e0 100644
   3.192  --- a/drivers/s390/net/qeth_main.c
   3.193  +++ b/drivers/s390/net/qeth_main.c
   3.194  @@ -4454,7 +4454,7 @@ qeth_send_packet(struct qeth_card *card,
   3.195 @@ -777,19 +796,20 @@ index dba7f7f..d9cc997 100644
   3.196   		[qeth_get_priority_queue(card, skb, ipv, cast_type)];
   3.197   
   3.198  -	if (skb_shinfo(skb)->tso_size)
   3.199 -+	if (skb_shinfo(skb)->gso_size)
   3.200 ++	if (skb_is_gso(skb))
   3.201   		large_send = card->options.large_send;
   3.202   
   3.203   	/*are we able to do TSO ? If so ,prepare and send it from here */
   3.204 -@@ -4501,7 +4501,7 @@ qeth_send_packet(struct qeth_card *card,
   3.205 +@@ -4501,8 +4501,7 @@ qeth_send_packet(struct qeth_card *card,
   3.206   		card->stats.tx_packets++;
   3.207   		card->stats.tx_bytes += skb->len;
   3.208   #ifdef CONFIG_QETH_PERF_STATS
   3.209  -		if (skb_shinfo(skb)->tso_size &&
   3.210 -+		if (skb_shinfo(skb)->gso_size &&
   3.211 - 		   !(large_send == QETH_LARGE_SEND_NO)) {
   3.212 +-		   !(large_send == QETH_LARGE_SEND_NO)) {
   3.213 ++		if (skb_is_gso(skb) && !(large_send == QETH_LARGE_SEND_NO)) {
   3.214   			card->perf_stats.large_send_bytes += skb->len;
   3.215   			card->perf_stats.large_send_cnt++;
   3.216 + 		}
   3.217  diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h
   3.218  index 1286dde..89cbf34 100644
   3.219  --- a/drivers/s390/net/qeth_tso.h
   3.220 @@ -817,7 +837,7 @@ index 93535f0..9269df7 100644
   3.221   /* compatibility with older code */
   3.222   #define SPARC_ETH_GSET		ETHTOOL_GSET
   3.223  diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
   3.224 -index 7fda03d..47b0965 100644
   3.225 +index 7fda03d..9865736 100644
   3.226  --- a/include/linux/netdevice.h
   3.227  +++ b/include/linux/netdevice.h
   3.228  @@ -230,7 +230,8 @@ enum netdev_state_t
   3.229 @@ -869,16 +889,17 @@ index 7fda03d..47b0965 100644
   3.230   	/* cpu id of processor entered to hard_start_xmit or -1,
   3.231   	   if nobody entered there.
   3.232   	 */
   3.233 -@@ -527,6 +539,8 @@ struct packet_type {
   3.234 +@@ -527,6 +539,9 @@ struct packet_type {
   3.235   					 struct net_device *,
   3.236   					 struct packet_type *,
   3.237   					 struct net_device *);
   3.238  +	struct sk_buff		*(*gso_segment)(struct sk_buff *skb,
   3.239  +						int features);
   3.240 ++	int			(*gso_send_check)(struct sk_buff *skb);
   3.241   	void			*af_packet_priv;
   3.242   	struct list_head	list;
   3.243   };
   3.244 -@@ -693,7 +707,8 @@ extern int		dev_change_name(struct net_d
   3.245 +@@ -693,7 +708,8 @@ extern int		dev_change_name(struct net_d
   3.246   extern int		dev_set_mtu(struct net_device *, int);
   3.247   extern int		dev_set_mac_address(struct net_device *,
   3.248   					    struct sockaddr *);
   3.249 @@ -888,7 +909,7 @@ index 7fda03d..47b0965 100644
   3.250   
   3.251   extern void		dev_init(void);
   3.252   
   3.253 -@@ -900,11 +915,43 @@ static inline void __netif_rx_complete(s
   3.254 +@@ -900,11 +916,43 @@ static inline void __netif_rx_complete(s
   3.255   	clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
   3.256   }
   3.257   
   3.258 @@ -934,7 +955,7 @@ index 7fda03d..47b0965 100644
   3.259   }
   3.260   
   3.261   /* These functions live elsewhere (drivers/net/net_init.c, but related) */
   3.262 -@@ -932,6 +979,7 @@ extern int		netdev_max_backlog;
   3.263 +@@ -932,6 +980,7 @@ extern int		netdev_max_backlog;
   3.264   extern int		weight_p;
   3.265   extern int		netdev_set_master(struct net_device *dev, struct net_device *master);
   3.266   extern int skb_checksum_help(struct sk_buff *skb, int inward);
   3.267 @@ -942,27 +963,28 @@ index 7fda03d..47b0965 100644
   3.268   #ifdef CONFIG_BUG
   3.269   extern void netdev_rx_csum_fault(struct net_device *dev);
   3.270   #else
   3.271 -@@ -951,6 +999,18 @@ #endif
   3.272 +@@ -951,6 +1000,19 @@ #endif
   3.273   
   3.274   extern void linkwatch_run_queue(void);
   3.275   
   3.276  +static inline int skb_gso_ok(struct sk_buff *skb, int features)
   3.277  +{
   3.278 -+	int feature = skb_shinfo(skb)->gso_size ?
   3.279 -+		      skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT : 0;
   3.280 ++	int feature = skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT;
   3.281  +	return (features & feature) == feature;
   3.282  +}
   3.283  +
   3.284  +static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
   3.285  +{
   3.286 -+	return !skb_gso_ok(skb, dev->features);
   3.287 ++	return skb_is_gso(skb) &&
   3.288 ++	       (!skb_gso_ok(skb, dev->features) ||
   3.289 ++		unlikely(skb->ip_summed != CHECKSUM_HW));
   3.290  +}
   3.291  +
   3.292   #endif /* __KERNEL__ */
   3.293   
   3.294   #endif	/* _LINUX_DEV_H */
   3.295  diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
   3.296 -index ad7cc22..b19d45d 100644
   3.297 +index ad7cc22..adfe3a8 100644
   3.298  --- a/include/linux/skbuff.h
   3.299  +++ b/include/linux/skbuff.h
   3.300  @@ -134,9 +134,10 @@ struct skb_frag_struct {
   3.301 @@ -1041,6 +1063,17 @@ index ad7cc22..b19d45d 100644
   3.302   
   3.303   static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
   3.304   				       int len, void *buffer)
   3.305 +@@ -1377,5 +1403,10 @@ #else /* CONFIG_NETFILTER */
   3.306 + static inline void nf_reset(struct sk_buff *skb) {}
   3.307 + #endif /* CONFIG_NETFILTER */
   3.308 + 
   3.309 ++static inline int skb_is_gso(const struct sk_buff *skb)
   3.310 ++{
   3.311 ++	return skb_shinfo(skb)->gso_size;
   3.312 ++}
   3.313 ++
   3.314 + #endif	/* __KERNEL__ */
   3.315 + #endif	/* _LINUX_SKBUFF_H */
   3.316  diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
   3.317  index b94d1ad..75b5b93 100644
   3.318  --- a/include/net/pkt_sched.h
   3.319 @@ -1063,13 +1096,14 @@ index b94d1ad..75b5b93 100644
   3.320   
   3.321   extern int tc_classify(struct sk_buff *skb, struct tcf_proto *tp,
   3.322  diff --git a/include/net/protocol.h b/include/net/protocol.h
   3.323 -index 6dc5970..0d2dcdb 100644
   3.324 +index 6dc5970..d516c58 100644
   3.325  --- a/include/net/protocol.h
   3.326  +++ b/include/net/protocol.h
   3.327 -@@ -37,6 +37,8 @@ #define MAX_INET_PROTOS	256		/* Must be 
   3.328 +@@ -37,6 +37,9 @@ #define MAX_INET_PROTOS	256		/* Must be 
   3.329   struct net_protocol {
   3.330   	int			(*handler)(struct sk_buff *skb);
   3.331   	void			(*err_handler)(struct sk_buff *skb, u32 info);
   3.332 ++	int			(*gso_send_check)(struct sk_buff *skb);
   3.333  +	struct sk_buff	       *(*gso_segment)(struct sk_buff *skb,
   3.334  +					       int features);
   3.335   	int			no_policy;
   3.336 @@ -1094,7 +1128,7 @@ index f63d0d5..a8e8d21 100644
   3.337   }
   3.338   
   3.339  diff --git a/include/net/tcp.h b/include/net/tcp.h
   3.340 -index 77f21c6..70e1d5f 100644
   3.341 +index 77f21c6..22dbbac 100644
   3.342  --- a/include/net/tcp.h
   3.343  +++ b/include/net/tcp.h
   3.344  @@ -552,13 +552,13 @@ #include <net/tcp_ecn.h>
   3.345 @@ -1113,10 +1147,11 @@ index 77f21c6..70e1d5f 100644
   3.346   }
   3.347   
   3.348   static inline void tcp_dec_pcount_approx(__u32 *count,
   3.349 -@@ -1063,6 +1063,8 @@ extern struct request_sock_ops tcp_reque
   3.350 +@@ -1063,6 +1063,9 @@ extern struct request_sock_ops tcp_reque
   3.351   
   3.352   extern int tcp_v4_destroy_sock(struct sock *sk);
   3.353   
   3.354 ++extern int tcp_v4_gso_send_check(struct sk_buff *skb);
   3.355  +extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features);
   3.356  +
   3.357   #ifdef CONFIG_PROC_FS
   3.358 @@ -1170,7 +1205,7 @@ index 0b33a7b..180e79b 100644
   3.359  + 			NETIF_F_TSO | NETIF_F_NO_CSUM | NETIF_F_GSO_ROBUST;
   3.360   }
   3.361  diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
   3.362 -index 2d24fb4..00b1128 100644
   3.363 +index 2d24fb4..b34e76f 100644
   3.364  --- a/net/bridge/br_forward.c
   3.365  +++ b/net/bridge/br_forward.c
   3.366  @@ -32,7 +32,7 @@ static inline int should_deliver(const s
   3.367 @@ -1178,7 +1213,7 @@ index 2d24fb4..00b1128 100644
   3.368   {
   3.369   	/* drop mtu oversized packets except tso */
   3.370  -	if (skb->len > skb->dev->mtu && !skb_shinfo(skb)->tso_size)
   3.371 -+	if (skb->len > skb->dev->mtu && !skb_shinfo(skb)->gso_size)
   3.372 ++	if (skb->len > skb->dev->mtu && !skb_is_gso(skb))
   3.373   		kfree_skb(skb);
   3.374   	else {
   3.375   #ifdef CONFIG_BRIDGE_NETFILTER
   3.376 @@ -1222,7 +1257,7 @@ index f36b35e..0617146 100644
   3.377   
   3.378   /* called with RTNL */
   3.379  diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
   3.380 -index 9e27373..588207f 100644
   3.381 +index 9e27373..b2dba74 100644
   3.382  --- a/net/bridge/br_netfilter.c
   3.383  +++ b/net/bridge/br_netfilter.c
   3.384  @@ -743,7 +743,7 @@ static int br_nf_dev_queue_xmit(struct s
   3.385 @@ -1230,12 +1265,12 @@ index 9e27373..588207f 100644
   3.386   	if (skb->protocol == htons(ETH_P_IP) &&
   3.387   	    skb->len > skb->dev->mtu &&
   3.388  -	    !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
   3.389 -+	    !skb_shinfo(skb)->gso_size)
   3.390 ++	    !skb_is_gso(skb))
   3.391   		return ip_fragment(skb, br_dev_queue_push_xmit);
   3.392   	else
   3.393   		return br_dev_queue_push_xmit(skb);
   3.394  diff --git a/net/core/dev.c b/net/core/dev.c
   3.395 -index 12a214c..32e1056 100644
   3.396 +index 12a214c..e814a89 100644
   3.397  --- a/net/core/dev.c
   3.398  +++ b/net/core/dev.c
   3.399  @@ -115,6 +115,7 @@ #include <linux/wireless.h>		/* Note : w
   3.400 @@ -1255,7 +1290,35 @@ index 12a214c..32e1056 100644
   3.401   {
   3.402   	struct packet_type *ptype;
   3.403   
   3.404 -@@ -1106,6 +1107,45 @@ out:	
   3.405 +@@ -1082,9 +1083,17 @@ int skb_checksum_help(struct sk_buff *sk
   3.406 + 	unsigned int csum;
   3.407 + 	int ret = 0, offset = skb->h.raw - skb->data;
   3.408 + 
   3.409 +-	if (inward) {
   3.410 +-		skb->ip_summed = CHECKSUM_NONE;
   3.411 +-		goto out;
   3.412 ++	if (inward)
   3.413 ++		goto out_set_summed;
   3.414 ++
   3.415 ++	if (unlikely(skb_shinfo(skb)->gso_size)) {
   3.416 ++		static int warned;
   3.417 ++
   3.418 ++		WARN_ON(!warned);
   3.419 ++		warned = 1;
   3.420 ++
   3.421 ++		/* Let GSO fix up the checksum. */
   3.422 ++		goto out_set_summed;
   3.423 + 	}
   3.424 + 
   3.425 + 	if (skb_cloned(skb)) {
   3.426 +@@ -1101,11 +1110,70 @@ int skb_checksum_help(struct sk_buff *sk
   3.427 + 	BUG_ON(skb->csum + 2 > offset);
   3.428 + 
   3.429 + 	*(u16*)(skb->h.raw + skb->csum) = csum_fold(csum);
   3.430 ++
   3.431 ++out_set_summed:
   3.432 + 	skb->ip_summed = CHECKSUM_NONE;
   3.433 + out:	
   3.434   	return ret;
   3.435   }
   3.436   
   3.437 @@ -1274,17 +1337,35 @@ index 12a214c..32e1056 100644
   3.438  +	struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
   3.439  +	struct packet_type *ptype;
   3.440  +	int type = skb->protocol;
   3.441 ++	int err;
   3.442  +
   3.443  +	BUG_ON(skb_shinfo(skb)->frag_list);
   3.444 -+	BUG_ON(skb->ip_summed != CHECKSUM_HW);
   3.445  +
   3.446  +	skb->mac.raw = skb->data;
   3.447  +	skb->mac_len = skb->nh.raw - skb->data;
   3.448  +	__skb_pull(skb, skb->mac_len);
   3.449  +
   3.450 ++	if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
   3.451 ++		static int warned;
   3.452 ++
   3.453 ++		WARN_ON(!warned);
   3.454 ++		warned = 1;
   3.455 ++
   3.456 ++		if (skb_header_cloned(skb) &&
   3.457 ++		    (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
   3.458 ++			return ERR_PTR(err);
   3.459 ++	}
   3.460 ++
   3.461  +	rcu_read_lock();
   3.462  +	list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) {
   3.463  +		if (ptype->type == type && !ptype->dev && ptype->gso_segment) {
   3.464 ++			if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
   3.465 ++				err = ptype->gso_send_check(skb);
   3.466 ++				segs = ERR_PTR(err);
   3.467 ++				if (err || skb_gso_ok(skb, features))
   3.468 ++					break;
   3.469 ++				__skb_push(skb, skb->data - skb->nh.raw);
   3.470 ++			}
   3.471  +			segs = ptype->gso_segment(skb, features);
   3.472  +			break;
   3.473  +		}
   3.474 @@ -1301,7 +1382,7 @@ index 12a214c..32e1056 100644
   3.475   /* Take action when hardware reception checksum errors are detected. */
   3.476   #ifdef CONFIG_BUG
   3.477   void netdev_rx_csum_fault(struct net_device *dev)
   3.478 -@@ -1142,75 +1182,108 @@ #else
   3.479 +@@ -1142,75 +1210,108 @@ #else
   3.480   #define illegal_highdma(dev, skb)	(0)
   3.481   #endif
   3.482   
   3.483 @@ -1469,7 +1550,7 @@ index 12a214c..32e1056 100644
   3.484   	}						\
   3.485   }
   3.486   
   3.487 -@@ -1246,9 +1319,13 @@ int dev_queue_xmit(struct sk_buff *skb)
   3.488 +@@ -1246,9 +1347,13 @@ int dev_queue_xmit(struct sk_buff *skb)
   3.489   	struct Qdisc *q;
   3.490   	int rc = -ENOMEM;
   3.491   
   3.492 @@ -1484,7 +1565,7 @@ index 12a214c..32e1056 100644
   3.493   		goto out_kfree_skb;
   3.494   
   3.495   	/* Fragmented skb is linearized if device does not support SG,
   3.496 -@@ -1257,25 +1334,26 @@ int dev_queue_xmit(struct sk_buff *skb)
   3.497 +@@ -1257,25 +1362,26 @@ int dev_queue_xmit(struct sk_buff *skb)
   3.498   	 */
   3.499   	if (skb_shinfo(skb)->nr_frags &&
   3.500   	    (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) &&
   3.501 @@ -1514,7 +1595,7 @@ index 12a214c..32e1056 100644
   3.502   
   3.503   	/* Updates of qdisc are serialized by queue_lock. 
   3.504   	 * The struct Qdisc which is pointed to by qdisc is now a 
   3.505 -@@ -1309,8 +1387,8 @@ #endif
   3.506 +@@ -1309,8 +1415,8 @@ #endif
   3.507   	/* The device has no queue. Common case for software devices:
   3.508   	   loopback, all the sorts of tunnels...
   3.509   
   3.510 @@ -1525,7 +1606,7 @@ index 12a214c..32e1056 100644
   3.511   	   counters.)
   3.512   	   However, it is possible, that they rely on protection
   3.513   	   made by us here.
   3.514 -@@ -1326,11 +1404,8 @@ #endif
   3.515 +@@ -1326,11 +1432,8 @@ #endif
   3.516   			HARD_TX_LOCK(dev, cpu);
   3.517   
   3.518   			if (!netif_queue_stopped(dev)) {
   3.519 @@ -1538,7 +1619,7 @@ index 12a214c..32e1056 100644
   3.520   					HARD_TX_UNLOCK(dev);
   3.521   					goto out;
   3.522   				}
   3.523 -@@ -1349,13 +1424,13 @@ #endif
   3.524 +@@ -1349,13 +1452,13 @@ #endif
   3.525   	}
   3.526   
   3.527   	rc = -ENETDOWN;
   3.528 @@ -1554,7 +1635,7 @@ index 12a214c..32e1056 100644
   3.529   	return rc;
   3.530   }
   3.531   
   3.532 -@@ -2670,7 +2745,7 @@ int register_netdevice(struct net_device
   3.533 +@@ -2670,7 +2773,7 @@ int register_netdevice(struct net_device
   3.534   	BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
   3.535   
   3.536   	spin_lock_init(&dev->queue_lock);
   3.537 @@ -1563,7 +1644,7 @@ index 12a214c..32e1056 100644
   3.538   	dev->xmit_lock_owner = -1;
   3.539   #ifdef CONFIG_NET_CLS_ACT
   3.540   	spin_lock_init(&dev->ingress_lock);
   3.541 -@@ -2714,9 +2789,7 @@ #endif
   3.542 +@@ -2714,9 +2817,7 @@ #endif
   3.543   
   3.544   	/* Fix illegal SG+CSUM combinations. */
   3.545   	if ((dev->features & NETIF_F_SG) &&
   3.546 @@ -1574,7 +1655,7 @@ index 12a214c..32e1056 100644
   3.547   		printk("%s: Dropping NETIF_F_SG since no checksum feature.\n",
   3.548   		       dev->name);
   3.549   		dev->features &= ~NETIF_F_SG;
   3.550 -@@ -3268,7 +3341,6 @@ subsys_initcall(net_dev_init);
   3.551 +@@ -3268,7 +3369,6 @@ subsys_initcall(net_dev_init);
   3.552   EXPORT_SYMBOL(__dev_get_by_index);
   3.553   EXPORT_SYMBOL(__dev_get_by_name);
   3.554   EXPORT_SYMBOL(__dev_remove_pack);
   3.555 @@ -2042,7 +2123,7 @@ index 3407f19..a0a25e0 100644
   3.556   
   3.557                   switch(flags & DN_RT_CNTL_MSK) {
   3.558  diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
   3.559 -index 97c276f..5ba719e 100644
   3.560 +index 97c276f..0a8c559 100644
   3.561  --- a/net/ipv4/af_inet.c
   3.562  +++ b/net/ipv4/af_inet.c
   3.563  @@ -68,6 +68,7 @@
   3.564 @@ -2053,10 +2134,44 @@ index 97c276f..5ba719e 100644
   3.565   #include <linux/errno.h>
   3.566   #include <linux/types.h>
   3.567   #include <linux/socket.h>
   3.568 -@@ -1084,6 +1085,54 @@ int inet_sk_rebuild_header(struct sock *
   3.569 +@@ -1084,6 +1085,88 @@ int inet_sk_rebuild_header(struct sock *
   3.570   
   3.571   EXPORT_SYMBOL(inet_sk_rebuild_header);
   3.572   
   3.573 ++static int inet_gso_send_check(struct sk_buff *skb)
   3.574 ++{
   3.575 ++	struct iphdr *iph;
   3.576 ++	struct net_protocol *ops;
   3.577 ++	int proto;
   3.578 ++	int ihl;
   3.579 ++	int err = -EINVAL;
   3.580 ++
   3.581 ++	if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
   3.582 ++		goto out;
   3.583 ++
   3.584 ++	iph = skb->nh.iph;
   3.585 ++	ihl = iph->ihl * 4;
   3.586 ++	if (ihl < sizeof(*iph))
   3.587 ++		goto out;
   3.588 ++
   3.589 ++	if (unlikely(!pskb_may_pull(skb, ihl)))
   3.590 ++		goto out;
   3.591 ++
   3.592 ++	skb->h.raw = __skb_pull(skb, ihl);
   3.593 ++	iph = skb->nh.iph;
   3.594 ++	proto = iph->protocol & (MAX_INET_PROTOS - 1);
   3.595 ++	err = -EPROTONOSUPPORT;
   3.596 ++
   3.597 ++	rcu_read_lock();
   3.598 ++	ops = rcu_dereference(inet_protos[proto]);
   3.599 ++	if (likely(ops && ops->gso_send_check))
   3.600 ++		err = ops->gso_send_check(skb);
   3.601 ++	rcu_read_unlock();
   3.602 ++
   3.603 ++out:
   3.604 ++	return err;
   3.605 ++}
   3.606 ++
   3.607  +static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
   3.608  +{
   3.609  +	struct sk_buff *segs = ERR_PTR(-EINVAL);
   3.610 @@ -2108,24 +2223,26 @@ index 97c276f..5ba719e 100644
   3.611   #ifdef CONFIG_IP_MULTICAST
   3.612   static struct net_protocol igmp_protocol = {
   3.613   	.handler =	igmp_rcv,
   3.614 -@@ -1093,6 +1142,7 @@ #endif
   3.615 +@@ -1093,6 +1176,8 @@ #endif
   3.616   static struct net_protocol tcp_protocol = {
   3.617   	.handler =	tcp_v4_rcv,
   3.618   	.err_handler =	tcp_v4_err,
   3.619 ++	.gso_send_check = tcp_v4_gso_send_check,
   3.620  +	.gso_segment =	tcp_tso_segment,
   3.621   	.no_policy =	1,
   3.622   };
   3.623   
   3.624 -@@ -1138,6 +1188,7 @@ static int ipv4_proc_init(void);
   3.625 +@@ -1138,6 +1223,8 @@ static int ipv4_proc_init(void);
   3.626   static struct packet_type ip_packet_type = {
   3.627   	.type = __constant_htons(ETH_P_IP),
   3.628   	.func = ip_rcv,
   3.629 ++	.gso_send_check = inet_gso_send_check,
   3.630  +	.gso_segment = inet_gso_segment,
   3.631   };
   3.632   
   3.633   static int __init inet_init(void)
   3.634  diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
   3.635 -index 8dcba38..19c3c73 100644
   3.636 +index 8dcba38..2de887c 100644
   3.637  --- a/net/ipv4/ip_output.c
   3.638  +++ b/net/ipv4/ip_output.c
   3.639  @@ -210,8 +210,7 @@ #if defined(CONFIG_NETFILTER) && defined
   3.640 @@ -2134,7 +2251,7 @@ index 8dcba38..19c3c73 100644
   3.641   #endif
   3.642  -	if (skb->len > dst_mtu(skb->dst) &&
   3.643  -	    !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
   3.644 -+	if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size)
   3.645 ++	if (skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb))
   3.646   		return ip_fragment(skb, ip_finish_output2);
   3.647   	else
   3.648   		return ip_finish_output2(skb);
   3.649 @@ -2182,7 +2299,7 @@ index 8dcba38..19c3c73 100644
   3.650   		int i;
   3.651   
   3.652  -		if (skb_shinfo(skb)->ufo_size)
   3.653 -+		if (skb_shinfo(skb)->gso_size)
   3.654 ++		if (skb_is_gso(skb))
   3.655   			len = size;
   3.656   		else {
   3.657   
   3.658 @@ -2372,6 +2489,35 @@ index e9a54ae..defe77a 100644
   3.659   					break;
   3.660   				pcount = tcp_skb_pcount(skb);
   3.661   			}
   3.662 +diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
   3.663 +index 233bdf2..b4240b4 100644
   3.664 +--- a/net/ipv4/tcp_ipv4.c
   3.665 ++++ b/net/ipv4/tcp_ipv4.c
   3.666 +@@ -495,6 +495,24 @@ void tcp_v4_send_check(struct sock *sk, 
   3.667 + 	}
   3.668 + }
   3.669 + 
   3.670 ++int tcp_v4_gso_send_check(struct sk_buff *skb)
   3.671 ++{
   3.672 ++	struct iphdr *iph;
   3.673 ++	struct tcphdr *th;
   3.674 ++
   3.675 ++	if (!pskb_may_pull(skb, sizeof(*th)))
   3.676 ++		return -EINVAL;
   3.677 ++
   3.678 ++	iph = skb->nh.iph;
   3.679 ++	th = skb->h.th;
   3.680 ++
   3.681 ++	th->check = 0;
   3.682 ++	th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0);
   3.683 ++	skb->csum = offsetof(struct tcphdr, check);
   3.684 ++	skb->ip_summed = CHECKSUM_HW;
   3.685 ++	return 0;
   3.686 ++}
   3.687 ++
   3.688 + /*
   3.689 +  *	This routine will send an RST to the other tcp.
   3.690 +  *
   3.691  diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
   3.692  index 310f2e6..ee01f69 100644
   3.693  --- a/net/ipv4/tcp_output.c
   3.694 @@ -2492,7 +2638,7 @@ index 310f2e6..ee01f69 100644
   3.695   	/* Use a previous sequence.  This should cause the other
   3.696   	 * end to send an ack.  Don't queue or clone SKB, just
   3.697  diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
   3.698 -index 32ad229..737c1db 100644
   3.699 +index 32ad229..62ead52 100644
   3.700  --- a/net/ipv4/xfrm4_output.c
   3.701  +++ b/net/ipv4/xfrm4_output.c
   3.702  @@ -9,6 +9,8 @@
   3.703 @@ -2546,7 +2692,7 @@ index 32ad229..737c1db 100644
   3.704  +	}
   3.705  +#endif
   3.706  +
   3.707 -+	if (!skb_shinfo(skb)->gso_size)
   3.708 ++	if (!skb_is_gso(skb))
   3.709  +		return xfrm4_output_finish2(skb);
   3.710  +
   3.711  +	skb->protocol = htons(ETH_P_IP);
   3.712 @@ -2581,7 +2727,7 @@ index 32ad229..737c1db 100644
   3.713   {
   3.714   	return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev,
   3.715  diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
   3.716 -index 5bf70b1..cf5d17e 100644
   3.717 +index 5bf70b1..33a5850 100644
   3.718  --- a/net/ipv6/ip6_output.c
   3.719  +++ b/net/ipv6/ip6_output.c
   3.720  @@ -147,7 +147,7 @@ static int ip6_output2(struct sk_buff *s
   3.721 @@ -2589,7 +2735,7 @@ index 5bf70b1..cf5d17e 100644
   3.722   int ip6_output(struct sk_buff *skb)
   3.723   {
   3.724  -	if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->ufo_size) ||
   3.725 -+	if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) ||
   3.726 ++	if ((skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb)) ||
   3.727   				dst_allfrag(skb->dst))
   3.728   		return ip6_fragment(skb, ip6_output2);
   3.729   	else
   3.730 @@ -2644,7 +2790,7 @@ index d511a88..ef56d5d 100644
   3.731   	/* compression */
   3.732   	plen = skb->len - hdr_len;
   3.733  diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
   3.734 -index 8024217..39bdeec 100644
   3.735 +index 8024217..e9ea338 100644
   3.736  --- a/net/ipv6/xfrm6_output.c
   3.737  +++ b/net/ipv6/xfrm6_output.c
   3.738  @@ -151,7 +151,7 @@ error_nolock:
   3.739 @@ -2673,7 +2819,7 @@ index 8024217..39bdeec 100644
   3.740  +{
   3.741  +	struct sk_buff *segs;
   3.742  +
   3.743 -+	if (!skb_shinfo(skb)->gso_size)
   3.744 ++	if (!skb_is_gso(skb))
   3.745  +		return xfrm6_output_finish2(skb);
   3.746  +
   3.747  +	skb->protocol = htons(ETH_P_IP);