diff options
author | kfraser@localhost.localdomain <kfraser@localhost.localdomain> | 2006-07-25 15:06:39 +0100 |
---|---|---|
committer | kfraser@localhost.localdomain <kfraser@localhost.localdomain> | 2006-07-25 15:06:39 +0100 |
commit | a4517dd065d9d6b05fd9969bd773096c69edb13a (patch) | |
tree | 31a61c47df25b99d5c1b7bcdba8a70ddc0029151 /patches | |
parent | 032e54ea22d8f717cad6abbfbe242ca8e9f6e0f6 (diff) | |
download | xen-a4517dd065d9d6b05fd9969bd773096c69edb13a.tar.gz xen-a4517dd065d9d6b05fd9969bd773096c69edb13a.tar.bz2 xen-a4517dd065d9d6b05fd9969bd773096c69edb13a.zip |
Split networking GSO patch into base portion plus additions.
Signed-off-by: Keir Fraser <keir@xensource.com>
Diffstat (limited to 'patches')
-rw-r--r-- | patches/linux-2.6.16.13/net-gso-0-base.patch (renamed from patches/linux-2.6.16.13/net-gso.patch) | 298 | ||||
-rw-r--r-- | patches/linux-2.6.16.13/net-gso-1-check-dodgy.patch | 27 | ||||
-rw-r--r-- | patches/linux-2.6.16.13/net-gso-2-checksum-fix.patch | 451 |
3 files changed, 551 insertions, 225 deletions
diff --git a/patches/linux-2.6.16.13/net-gso.patch b/patches/linux-2.6.16.13/net-gso-0-base.patch index eb5d6b0ab7..4c69d1e4a6 100644 --- a/patches/linux-2.6.16.13/net-gso.patch +++ b/patches/linux-2.6.16.13/net-gso-0-base.patch @@ -104,7 +104,7 @@ index dd41049..6615583 100644 if (skb_shinfo(skb)->nr_frags == 0) { struct cp_desc *txd = &cp->tx_ring[entry]; diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c -index a24200d..29d9218 100644 +index a24200d..b5e39a1 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -1593,7 +1593,7 @@ bnx2_tx_int(struct bnx2 *bp) @@ -112,7 +112,7 @@ index a24200d..29d9218 100644 #ifdef BCM_TSO /* partial BD completions possible with TSO packets */ - if (skb_shinfo(skb)->tso_size) { -+ if (skb_is_gso(skb)) { ++ if (skb_shinfo(skb)->gso_size) { u16 last_idx, last_ring_idx; last_idx = sw_cons + @@ -178,7 +178,7 @@ index bcf9f17..e970921 100644 bond_dev->features |= NETIF_F_LLTX; diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c -index 30ff8ea..7d72e16 100644 +index 30ff8ea..7b7d360 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1419,7 +1419,7 @@ int t1_start_xmit(struct sk_buff *skb, s @@ -186,7 +186,7 @@ index 30ff8ea..7d72e16 100644 #ifdef NETIF_F_TSO - if (skb_shinfo(skb)->tso_size) { -+ if (skb_is_gso(skb)) { ++ if (skb_shinfo(skb)->gso_size) { int eth_type; struct cpl_tx_pkt_lso *hdr; @@ -200,7 +200,7 @@ index 30ff8ea..7d72e16 100644 cpl = (struct cpl_tx_pkt *)hdr; sge->stats.tx_lso_pkts++; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c -index fa29402..96ddc24 100644 +index fa29402..681d284 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2526,7 +2526,7 @@ #ifdef NETIF_F_TSO @@ -208,7 +208,7 @@ index fa29402..96ddc24 100644 int err; - if (skb_shinfo(skb)->tso_size) { -+ if (skb_is_gso(skb)) { ++ if (skb_shinfo(skb)->gso_size) { if (skb_header_cloned(skb)) { err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); if (err) @@ -226,7 +226,7 @@ index fa29402..96ddc24 100644 * DMAd to the controller */ if (!skb->data_len && tx_ring->last_tx_tso && - !skb_shinfo(skb)->tso_size) { -+ !skb_is_gso(skb)) { ++ !skb_shinfo(skb)->gso_size) { tx_ring->last_tx_tso = 0; size -= 4; } @@ -239,18 +239,17 @@ index fa29402..96ddc24 100644 /* The controller does a simple calculation to * make sure there is enough room in the FIFO before * initiating the DMA for each buffer. The calc is: -@@ -2934,8 +2934,7 @@ #endif - +@@ -2935,7 +2935,7 @@ #endif #ifdef NETIF_F_TSO /* Controller Erratum workaround */ -- if (!skb->data_len && tx_ring->last_tx_tso && + if (!skb->data_len && tx_ring->last_tx_tso && - !skb_shinfo(skb)->tso_size) -+ if (!skb->data_len && tx_ring->last_tx_tso && !skb_is_gso(skb)) ++ !skb_shinfo(skb)->gso_size) count++; #endif diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c -index 3682ec6..c6ca459 100644 +index 3682ec6..c35f16e 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -482,9 +482,9 @@ #define LPA_1000HALF 0x0400 @@ -280,7 +279,7 @@ index 3682ec6..c6ca459 100644 #ifdef NETIF_F_TSO - if (skb_shinfo(skb)->tso_size) - tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT); -+ if (skb_is_gso(skb)) ++ if (skb_shinfo(skb)->gso_size) + tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT); else #endif @@ -451,7 +450,7 @@ index a9f49f0..339d4a7 100644 } diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c -index f9f77e4..7d187d0 100644 +index f9f77e4..bdab369 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1163,7 +1163,7 @@ #ifdef NETIF_F_TSO @@ -459,7 +458,7 @@ index f9f77e4..7d187d0 100644 int err; - if(likely(skb_shinfo(skb)->tso_size)) { -+ if (likely(skb_is_gso(skb))) { ++ if(likely(skb_shinfo(skb)->gso_size)) { if (skb_header_cloned(skb)) { err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); if (err) @@ -473,7 +472,7 @@ index f9f77e4..7d187d0 100644 skb->nh.iph->check = 0; skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr, diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c -index 690a1aa..3843e0a 100644 +index 690a1aa..9bcaa80 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -74,7 +74,7 @@ static void emulate_large_send_offload(s @@ -490,7 +489,7 @@ index 690a1aa..3843e0a 100644 #ifdef LOOPBACK_TSO - if (skb_shinfo(skb)->tso_size) { -+ if (skb_is_gso(skb)) { ++ if (skb_shinfo(skb)->gso_size) { BUG_ON(skb->protocol != htons(ETH_P_IP)); BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP); @@ -601,7 +600,7 @@ index b7f00d6..439f45f 100644 writeq(val64, &tx_fifo->List_Control); diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c -index 0618cd5..aa06a82 100644 +index 0618cd5..2a55eb3 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1125,7 +1125,7 @@ static unsigned tx_le_req(const struct s @@ -609,7 +608,7 @@ index 0618cd5..aa06a82 100644 count += skb_shinfo(skb)->nr_frags * count; - if (skb_shinfo(skb)->tso_size) -+ if (skb_is_gso(skb)) ++ if (skb_shinfo(skb)->gso_size) ++count; if (skb->ip_summed == CHECKSUM_HW) @@ -668,7 +667,7 @@ index 5b1af39..11de5af 100644 np->stats.rx_missed_errors += ioread32(ioaddr + RxMissed) & 0xffff; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c -index 4c76cb7..3d62abc 100644 +index 4c76cb7..30c48c9 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -340,7 +340,7 @@ #define typhoon_synchronize_irq(x) synch @@ -680,24 +679,6 @@ index 4c76cb7..3d62abc 100644 #define TSO_NUM_DESCRIPTORS 2 #define TSO_OFFLOAD_ON TYPHOON_OFFLOAD_TCP_SEGMENT #else -@@ -805,7 +805,7 @@ typhoon_start_tx(struct sk_buff *skb, st - * If problems develop with TSO, check this first. - */ - numDesc = skb_shinfo(skb)->nr_frags + 1; -- if(skb_tso_size(skb)) -+ if (skb_is_gso(skb)) - numDesc++; - - /* When checking for free space in the ring, we need to also -@@ -845,7 +845,7 @@ typhoon_start_tx(struct sk_buff *skb, st - TYPHOON_TX_PF_VLAN_TAG_SHIFT); - } - -- if(skb_tso_size(skb)) { -+ if (skb_is_gso(skb)) { - first_txd->processFlags |= TYPHOON_TX_PF_TCP_SEGMENT; - first_txd->numDesc++; - diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index ed1f837..2eb6b5f 100644 --- a/drivers/net/via-velocity.c @@ -788,7 +769,7 @@ index 82cb4af..57cec40 100644 static inline struct qeth_eddp_context * diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c -index dba7f7f..a3ea8e0 100644 +index dba7f7f..d9cc997 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -4454,7 +4454,7 @@ qeth_send_packet(struct qeth_card *card, @@ -796,20 +777,19 @@ index dba7f7f..a3ea8e0 100644 [qeth_get_priority_queue(card, skb, ipv, cast_type)]; - if (skb_shinfo(skb)->tso_size) -+ if (skb_is_gso(skb)) ++ if (skb_shinfo(skb)->gso_size) large_send = card->options.large_send; /*are we able to do TSO ? If so ,prepare and send it from here */ -@@ -4501,8 +4501,7 @@ qeth_send_packet(struct qeth_card *card, +@@ -4501,7 +4501,7 @@ qeth_send_packet(struct qeth_card *card, card->stats.tx_packets++; card->stats.tx_bytes += skb->len; #ifdef CONFIG_QETH_PERF_STATS - if (skb_shinfo(skb)->tso_size && -- !(large_send == QETH_LARGE_SEND_NO)) { -+ if (skb_is_gso(skb) && !(large_send == QETH_LARGE_SEND_NO)) { ++ if (skb_shinfo(skb)->gso_size && + !(large_send == QETH_LARGE_SEND_NO)) { card->perf_stats.large_send_bytes += skb->len; card->perf_stats.large_send_cnt++; - } diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h index 1286dde..89cbf34 100644 --- a/drivers/s390/net/qeth_tso.h @@ -837,7 +817,7 @@ index 93535f0..9269df7 100644 /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h -index 7fda03d..9865736 100644 +index 7fda03d..47b0965 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -230,7 +230,8 @@ enum netdev_state_t @@ -889,17 +869,16 @@ index 7fda03d..9865736 100644 /* cpu id of processor entered to hard_start_xmit or -1, if nobody entered there. */ -@@ -527,6 +539,9 @@ struct packet_type { +@@ -527,6 +539,8 @@ struct packet_type { struct net_device *, struct packet_type *, struct net_device *); + struct sk_buff *(*gso_segment)(struct sk_buff *skb, + int features); -+ int (*gso_send_check)(struct sk_buff *skb); void *af_packet_priv; struct list_head list; }; -@@ -693,7 +708,8 @@ extern int dev_change_name(struct net_d +@@ -693,7 +707,8 @@ extern int dev_change_name(struct net_d extern int dev_set_mtu(struct net_device *, int); extern int dev_set_mac_address(struct net_device *, struct sockaddr *); @@ -909,7 +888,7 @@ index 7fda03d..9865736 100644 extern void dev_init(void); -@@ -900,11 +916,43 @@ static inline void __netif_rx_complete(s +@@ -900,11 +915,43 @@ static inline void __netif_rx_complete(s clear_bit(__LINK_STATE_RX_SCHED, &dev->state); } @@ -955,7 +934,7 @@ index 7fda03d..9865736 100644 } /* These functions live elsewhere (drivers/net/net_init.c, but related) */ -@@ -932,6 +980,7 @@ extern int netdev_max_backlog; +@@ -932,6 +979,7 @@ extern int netdev_max_backlog; extern int weight_p; extern int netdev_set_master(struct net_device *dev, struct net_device *master); extern int skb_checksum_help(struct sk_buff *skb, int inward); @@ -963,28 +942,27 @@ index 7fda03d..9865736 100644 #ifdef CONFIG_BUG extern void netdev_rx_csum_fault(struct net_device *dev); #else -@@ -951,6 +1000,19 @@ #endif +@@ -951,6 +999,18 @@ #endif extern void linkwatch_run_queue(void); +static inline int skb_gso_ok(struct sk_buff *skb, int features) +{ -+ int feature = skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT; ++ int feature = skb_shinfo(skb)->gso_size ? ++ skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT : 0; + return (features & feature) == feature; +} + +static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb) +{ -+ return skb_is_gso(skb) && -+ (!skb_gso_ok(skb, dev->features) || -+ unlikely(skb->ip_summed != CHECKSUM_HW)); ++ return !skb_gso_ok(skb, dev->features); +} + #endif /* __KERNEL__ */ #endif /* _LINUX_DEV_H */ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h -index ad7cc22..adfe3a8 100644 +index ad7cc22..b19d45d 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -134,9 +134,10 @@ struct skb_frag_struct { @@ -1063,17 +1041,6 @@ index ad7cc22..adfe3a8 100644 static inline void *skb_header_pointer(const struct sk_buff *skb, int offset, int len, void *buffer) -@@ -1377,5 +1403,10 @@ #else /* CONFIG_NETFILTER */ - static inline void nf_reset(struct sk_buff *skb) {} - #endif /* CONFIG_NETFILTER */ - -+static inline int skb_is_gso(const struct sk_buff *skb) -+{ -+ return skb_shinfo(skb)->gso_size; -+} -+ - #endif /* __KERNEL__ */ - #endif /* _LINUX_SKBUFF_H */ diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index b94d1ad..75b5b93 100644 --- a/include/net/pkt_sched.h @@ -1096,14 +1063,13 @@ index b94d1ad..75b5b93 100644 extern int tc_classify(struct sk_buff *skb, struct tcf_proto *tp, diff --git a/include/net/protocol.h b/include/net/protocol.h -index 6dc5970..d516c58 100644 +index 6dc5970..0d2dcdb 100644 --- a/include/net/protocol.h +++ b/include/net/protocol.h -@@ -37,6 +37,9 @@ #define MAX_INET_PROTOS 256 /* Must be +@@ -37,6 +37,8 @@ #define MAX_INET_PROTOS 256 /* Must be struct net_protocol { int (*handler)(struct sk_buff *skb); void (*err_handler)(struct sk_buff *skb, u32 info); -+ int (*gso_send_check)(struct sk_buff *skb); + struct sk_buff *(*gso_segment)(struct sk_buff *skb, + int features); int no_policy; @@ -1128,7 +1094,7 @@ index f63d0d5..a8e8d21 100644 } diff --git a/include/net/tcp.h b/include/net/tcp.h -index 77f21c6..22dbbac 100644 +index 77f21c6..70e1d5f 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -552,13 +552,13 @@ #include <net/tcp_ecn.h> @@ -1147,11 +1113,10 @@ index 77f21c6..22dbbac 100644 } static inline void tcp_dec_pcount_approx(__u32 *count, -@@ -1063,6 +1063,9 @@ extern struct request_sock_ops tcp_reque +@@ -1063,6 +1063,8 @@ extern struct request_sock_ops tcp_reque extern int tcp_v4_destroy_sock(struct sock *sk); -+extern int tcp_v4_gso_send_check(struct sk_buff *skb); +extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features); + #ifdef CONFIG_PROC_FS @@ -1205,7 +1170,7 @@ index 0b33a7b..180e79b 100644 + NETIF_F_TSO | NETIF_F_NO_CSUM | NETIF_F_GSO_ROBUST; } diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c -index 2d24fb4..b34e76f 100644 +index 2d24fb4..00b1128 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -32,7 +32,7 @@ static inline int should_deliver(const s @@ -1213,7 +1178,7 @@ index 2d24fb4..b34e76f 100644 { /* drop mtu oversized packets except tso */ - if (skb->len > skb->dev->mtu && !skb_shinfo(skb)->tso_size) -+ if (skb->len > skb->dev->mtu && !skb_is_gso(skb)) ++ if (skb->len > skb->dev->mtu && !skb_shinfo(skb)->gso_size) kfree_skb(skb); else { #ifdef CONFIG_BRIDGE_NETFILTER @@ -1257,7 +1222,7 @@ index f36b35e..0617146 100644 /* called with RTNL */ diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c -index 9e27373..b2dba74 100644 +index 9e27373..588207f 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -743,7 +743,7 @@ static int br_nf_dev_queue_xmit(struct s @@ -1265,12 +1230,12 @@ index 9e27373..b2dba74 100644 if (skb->protocol == htons(ETH_P_IP) && skb->len > skb->dev->mtu && - !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size)) -+ !skb_is_gso(skb)) ++ !skb_shinfo(skb)->gso_size) return ip_fragment(skb, br_dev_queue_push_xmit); else return br_dev_queue_push_xmit(skb); diff --git a/net/core/dev.c b/net/core/dev.c -index 12a214c..e814a89 100644 +index 12a214c..32e1056 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -115,6 +115,7 @@ #include <linux/wireless.h> /* Note : w @@ -1290,35 +1255,7 @@ index 12a214c..e814a89 100644 { struct packet_type *ptype; -@@ -1082,9 +1083,17 @@ int skb_checksum_help(struct sk_buff *sk - unsigned int csum; - int ret = 0, offset = skb->h.raw - skb->data; - -- if (inward) { -- skb->ip_summed = CHECKSUM_NONE; -- goto out; -+ if (inward) -+ goto out_set_summed; -+ -+ if (unlikely(skb_shinfo(skb)->gso_size)) { -+ static int warned; -+ -+ WARN_ON(!warned); -+ warned = 1; -+ -+ /* Let GSO fix up the checksum. */ -+ goto out_set_summed; - } - - if (skb_cloned(skb)) { -@@ -1101,11 +1110,70 @@ int skb_checksum_help(struct sk_buff *sk - BUG_ON(skb->csum + 2 > offset); - - *(u16*)(skb->h.raw + skb->csum) = csum_fold(csum); -+ -+out_set_summed: - skb->ip_summed = CHECKSUM_NONE; - out: +@@ -1106,6 +1107,45 @@ out: return ret; } @@ -1337,35 +1274,17 @@ index 12a214c..e814a89 100644 + struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); + struct packet_type *ptype; + int type = skb->protocol; -+ int err; + + BUG_ON(skb_shinfo(skb)->frag_list); ++ BUG_ON(skb->ip_summed != CHECKSUM_HW); + + skb->mac.raw = skb->data; + skb->mac_len = skb->nh.raw - skb->data; + __skb_pull(skb, skb->mac_len); + -+ if (unlikely(skb->ip_summed != CHECKSUM_HW)) { -+ static int warned; -+ -+ WARN_ON(!warned); -+ warned = 1; -+ -+ if (skb_header_cloned(skb) && -+ (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) -+ return ERR_PTR(err); -+ } -+ + rcu_read_lock(); + list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) { + if (ptype->type == type && !ptype->dev && ptype->gso_segment) { -+ if (unlikely(skb->ip_summed != CHECKSUM_HW)) { -+ err = ptype->gso_send_check(skb); -+ segs = ERR_PTR(err); -+ if (err || skb_gso_ok(skb, features)) -+ break; -+ __skb_push(skb, skb->data - skb->nh.raw); -+ } + segs = ptype->gso_segment(skb, features); + break; + } @@ -1382,7 +1301,7 @@ index 12a214c..e814a89 100644 /* Take action when hardware reception checksum errors are detected. */ #ifdef CONFIG_BUG void netdev_rx_csum_fault(struct net_device *dev) -@@ -1142,75 +1210,108 @@ #else +@@ -1142,75 +1182,108 @@ #else #define illegal_highdma(dev, skb) (0) #endif @@ -1550,7 +1469,7 @@ index 12a214c..e814a89 100644 } \ } -@@ -1246,9 +1347,13 @@ int dev_queue_xmit(struct sk_buff *skb) +@@ -1246,9 +1319,13 @@ int dev_queue_xmit(struct sk_buff *skb) struct Qdisc *q; int rc = -ENOMEM; @@ -1565,7 +1484,7 @@ index 12a214c..e814a89 100644 goto out_kfree_skb; /* Fragmented skb is linearized if device does not support SG, -@@ -1257,25 +1362,26 @@ int dev_queue_xmit(struct sk_buff *skb) +@@ -1257,25 +1334,26 @@ int dev_queue_xmit(struct sk_buff *skb) */ if (skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) && @@ -1595,7 +1514,7 @@ index 12a214c..e814a89 100644 /* Updates of qdisc are serialized by queue_lock. * The struct Qdisc which is pointed to by qdisc is now a -@@ -1309,8 +1415,8 @@ #endif +@@ -1309,8 +1387,8 @@ #endif /* The device has no queue. Common case for software devices: loopback, all the sorts of tunnels... @@ -1606,7 +1525,7 @@ index 12a214c..e814a89 100644 counters.) However, it is possible, that they rely on protection made by us here. -@@ -1326,11 +1432,8 @@ #endif +@@ -1326,11 +1404,8 @@ #endif HARD_TX_LOCK(dev, cpu); if (!netif_queue_stopped(dev)) { @@ -1619,7 +1538,7 @@ index 12a214c..e814a89 100644 HARD_TX_UNLOCK(dev); goto out; } -@@ -1349,13 +1452,13 @@ #endif +@@ -1349,13 +1424,13 @@ #endif } rc = -ENETDOWN; @@ -1635,7 +1554,7 @@ index 12a214c..e814a89 100644 return rc; } -@@ -2670,7 +2773,7 @@ int register_netdevice(struct net_device +@@ -2670,7 +2745,7 @@ int register_netdevice(struct net_device BUG_ON(dev->reg_state != NETREG_UNINITIALIZED); spin_lock_init(&dev->queue_lock); @@ -1644,7 +1563,7 @@ index 12a214c..e814a89 100644 dev->xmit_lock_owner = -1; #ifdef CONFIG_NET_CLS_ACT spin_lock_init(&dev->ingress_lock); -@@ -2714,9 +2817,7 @@ #endif +@@ -2714,9 +2789,7 @@ #endif /* Fix illegal SG+CSUM combinations. */ if ((dev->features & NETIF_F_SG) && @@ -1655,7 +1574,7 @@ index 12a214c..e814a89 100644 printk("%s: Dropping NETIF_F_SG since no checksum feature.\n", dev->name); dev->features &= ~NETIF_F_SG; -@@ -3268,7 +3369,6 @@ subsys_initcall(net_dev_init); +@@ -3268,7 +3341,6 @@ subsys_initcall(net_dev_init); EXPORT_SYMBOL(__dev_get_by_index); EXPORT_SYMBOL(__dev_get_by_name); EXPORT_SYMBOL(__dev_remove_pack); @@ -2123,7 +2042,7 @@ index 3407f19..a0a25e0 100644 switch(flags & DN_RT_CNTL_MSK) { diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c -index 97c276f..0a8c559 100644 +index 97c276f..5ba719e 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -68,6 +68,7 @@ @@ -2134,44 +2053,10 @@ index 97c276f..0a8c559 100644 #include <linux/errno.h> #include <linux/types.h> #include <linux/socket.h> -@@ -1084,6 +1085,88 @@ int inet_sk_rebuild_header(struct sock * +@@ -1084,6 +1085,54 @@ int inet_sk_rebuild_header(struct sock * EXPORT_SYMBOL(inet_sk_rebuild_header); -+static int inet_gso_send_check(struct sk_buff *skb) -+{ -+ struct iphdr *iph; -+ struct net_protocol *ops; -+ int proto; -+ int ihl; -+ int err = -EINVAL; -+ -+ if (unlikely(!pskb_may_pull(skb, sizeof(*iph)))) -+ goto out; -+ -+ iph = skb->nh.iph; -+ ihl = iph->ihl * 4; -+ if (ihl < sizeof(*iph)) -+ goto out; -+ -+ if (unlikely(!pskb_may_pull(skb, ihl))) -+ goto out; -+ -+ skb->h.raw = __skb_pull(skb, ihl); -+ iph = skb->nh.iph; -+ proto = iph->protocol & (MAX_INET_PROTOS - 1); -+ err = -EPROTONOSUPPORT; -+ -+ rcu_read_lock(); -+ ops = rcu_dereference(inet_protos[proto]); -+ if (likely(ops && ops->gso_send_check)) -+ err = ops->gso_send_check(skb); -+ rcu_read_unlock(); -+ -+out: -+ return err; -+} -+ +static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features) +{ + struct sk_buff *segs = ERR_PTR(-EINVAL); @@ -2223,26 +2108,24 @@ index 97c276f..0a8c559 100644 #ifdef CONFIG_IP_MULTICAST static struct net_protocol igmp_protocol = { .handler = igmp_rcv, -@@ -1093,6 +1176,8 @@ #endif +@@ -1093,6 +1142,7 @@ #endif static struct net_protocol tcp_protocol = { .handler = tcp_v4_rcv, .err_handler = tcp_v4_err, -+ .gso_send_check = tcp_v4_gso_send_check, + .gso_segment = tcp_tso_segment, .no_policy = 1, }; -@@ -1138,6 +1223,8 @@ static int ipv4_proc_init(void); +@@ -1138,6 +1188,7 @@ static int ipv4_proc_init(void); static struct packet_type ip_packet_type = { .type = __constant_htons(ETH_P_IP), .func = ip_rcv, -+ .gso_send_check = inet_gso_send_check, + .gso_segment = inet_gso_segment, }; static int __init inet_init(void) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c -index 8dcba38..2de887c 100644 +index 8dcba38..19c3c73 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -210,8 +210,7 @@ #if defined(CONFIG_NETFILTER) && defined @@ -2251,7 +2134,7 @@ index 8dcba38..2de887c 100644 #endif - if (skb->len > dst_mtu(skb->dst) && - !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size)) -+ if (skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb)) ++ if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) return ip_fragment(skb, ip_finish_output2); else return ip_finish_output2(skb); @@ -2299,7 +2182,7 @@ index 8dcba38..2de887c 100644 int i; - if (skb_shinfo(skb)->ufo_size) -+ if (skb_is_gso(skb)) ++ if (skb_shinfo(skb)->gso_size) len = size; else { @@ -2342,7 +2225,7 @@ index d64e2ec..7494823 100644 err = ipcomp_compress(x, skb); iph = skb->nh.iph; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c -index 00aa80e..30c81a8 100644 +index 00aa80e..84130c9 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -257,6 +257,7 @@ #include <linux/smp_lock.h> @@ -2398,7 +2281,7 @@ index 00aa80e..30c81a8 100644 from += copy; copied += copy; -@@ -2026,6 +2021,77 @@ int tcp_getsockopt(struct sock *sk, int +@@ -2026,6 +2021,71 @@ int tcp_getsockopt(struct sock *sk, int } @@ -2423,19 +2306,13 @@ index 00aa80e..30c81a8 100644 + if (!pskb_may_pull(skb, thlen)) + goto out; + ++ segs = NULL; ++ if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) ++ goto out; ++ + oldlen = (u16)~skb->len; + __skb_pull(skb, thlen); + -+ if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { -+ /* Packet is from an untrusted source, reset gso_segs. */ -+ int mss = skb_shinfo(skb)->gso_size; -+ -+ skb_shinfo(skb)->gso_segs = (skb->len + mss - 1) / mss; -+ -+ segs = NULL; -+ goto out; -+ } -+ + segs = skb_segment(skb, features); + if (IS_ERR(segs)) + goto out; @@ -2489,35 +2366,6 @@ index e9a54ae..defe77a 100644 break; pcount = tcp_skb_pcount(skb); } -diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c -index 233bdf2..b4240b4 100644 ---- a/net/ipv4/tcp_ipv4.c -+++ b/net/ipv4/tcp_ipv4.c -@@ -495,6 +495,24 @@ void tcp_v4_send_check(struct sock *sk, - } - } - -+int tcp_v4_gso_send_check(struct sk_buff *skb) -+{ -+ struct iphdr *iph; -+ struct tcphdr *th; -+ -+ if (!pskb_may_pull(skb, sizeof(*th))) -+ return -EINVAL; -+ -+ iph = skb->nh.iph; -+ th = skb->h.th; -+ -+ th->check = 0; -+ th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0); -+ skb->csum = offsetof(struct tcphdr, check); -+ skb->ip_summed = CHECKSUM_HW; -+ return 0; -+} -+ - /* - * This routine will send an RST to the other tcp. - * diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 310f2e6..ee01f69 100644 --- a/net/ipv4/tcp_output.c @@ -2638,7 +2486,7 @@ index 310f2e6..ee01f69 100644 /* Use a previous sequence. This should cause the other * end to send an ack. Don't queue or clone SKB, just diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c -index 32ad229..62ead52 100644 +index 32ad229..737c1db 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -9,6 +9,8 @@ @@ -2692,7 +2540,7 @@ index 32ad229..62ead52 100644 + } +#endif + -+ if (!skb_is_gso(skb)) ++ if (!skb_shinfo(skb)->gso_size) + return xfrm4_output_finish2(skb); + + skb->protocol = htons(ETH_P_IP); @@ -2727,7 +2575,7 @@ index 32ad229..62ead52 100644 { return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev, diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c -index 5bf70b1..33a5850 100644 +index 5bf70b1..cf5d17e 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -147,7 +147,7 @@ static int ip6_output2(struct sk_buff *s @@ -2735,7 +2583,7 @@ index 5bf70b1..33a5850 100644 int ip6_output(struct sk_buff *skb) { - if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->ufo_size) || -+ if ((skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb)) || ++ if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) || dst_allfrag(skb->dst)) return ip6_fragment(skb, ip6_output2); else @@ -2790,7 +2638,7 @@ index d511a88..ef56d5d 100644 /* compression */ plen = skb->len - hdr_len; diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c -index 8024217..e9ea338 100644 +index 8024217..39bdeec 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -151,7 +151,7 @@ error_nolock: @@ -2819,7 +2667,7 @@ index 8024217..e9ea338 100644 +{ + struct sk_buff *segs; + -+ if (!skb_is_gso(skb)) ++ if (!skb_shinfo(skb)->gso_size) + return xfrm6_output_finish2(skb); + + skb->protocol = htons(ETH_P_IP); diff --git a/patches/linux-2.6.16.13/net-gso-1-check-dodgy.patch b/patches/linux-2.6.16.13/net-gso-1-check-dodgy.patch new file mode 100644 index 0000000000..ab8812af61 --- /dev/null +++ b/patches/linux-2.6.16.13/net-gso-1-check-dodgy.patch @@ -0,0 +1,27 @@ +diff -urp a/net/ipv4/tcp.c b/net/ipv4/tcp.c +--- a/net/ipv4/tcp.c 2006-07-25 14:42:53.194910626 +0100 ++++ b/net/ipv4/tcp.c 2006-07-25 14:41:00.955501910 +0100 +@@ -2042,13 +2042,19 @@ struct sk_buff *tcp_tso_segment(struct s + if (!pskb_may_pull(skb, thlen)) + goto out; + +- segs = NULL; +- if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) +- goto out; +- + oldlen = (u16)~skb->len; + __skb_pull(skb, thlen); + ++ if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { ++ /* Packet is from an untrusted source, reset gso_segs. */ ++ int mss = skb_shinfo(skb)->gso_size; ++ ++ skb_shinfo(skb)->gso_segs = (skb->len + mss - 1) / mss; ++ ++ segs = NULL; ++ goto out; ++ } ++ + segs = skb_segment(skb, features); + if (IS_ERR(segs)) + goto out; diff --git a/patches/linux-2.6.16.13/net-gso-2-checksum-fix.patch b/patches/linux-2.6.16.13/net-gso-2-checksum-fix.patch new file mode 100644 index 0000000000..d8b7ba7a75 --- /dev/null +++ b/patches/linux-2.6.16.13/net-gso-2-checksum-fix.patch @@ -0,0 +1,451 @@ +diff -urp a/drivers/net/bnx2.c b/drivers/net/bnx2.c +--- a/drivers/net/bnx2.c 2006-07-25 14:41:00.905507519 +0100 ++++ b/drivers/net/bnx2.c 2006-07-25 14:36:00.288561400 +0100 +@@ -1593,7 +1593,7 @@ bnx2_tx_int(struct bnx2 *bp) + skb = tx_buf->skb; + #ifdef BCM_TSO + /* partial BD completions possible with TSO packets */ +- if (skb_shinfo(skb)->gso_size) { ++ if (skb_is_gso(skb)) { + u16 last_idx, last_ring_idx; + + last_idx = sw_cons + +diff -urp a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c +--- a/drivers/net/chelsio/sge.c 2006-07-25 14:41:00.908507183 +0100 ++++ b/drivers/net/chelsio/sge.c 2006-07-25 14:36:00.291561087 +0100 +@@ -1419,7 +1419,7 @@ int t1_start_xmit(struct sk_buff *skb, s + struct cpl_tx_pkt *cpl; + + #ifdef NETIF_F_TSO +- if (skb_shinfo(skb)->gso_size) { ++ if (skb_is_gso(skb)) { + int eth_type; + struct cpl_tx_pkt_lso *hdr; + +diff -urp a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c +--- a/drivers/net/e1000/e1000_main.c 2006-07-25 14:41:00.910506958 +0100 ++++ b/drivers/net/e1000/e1000_main.c 2006-07-25 14:36:00.293560878 +0100 +@@ -2526,7 +2526,7 @@ e1000_tso(struct e1000_adapter *adapter, + uint8_t ipcss, ipcso, tucss, tucso, hdr_len; + int err; + +- if (skb_shinfo(skb)->gso_size) { ++ if (skb_is_gso(skb)) { + if (skb_header_cloned(skb)) { + err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); + if (err) +@@ -2651,7 +2651,7 @@ e1000_tx_map(struct e1000_adapter *adapt + * tso gets written back prematurely before the data is fully + * DMAd to the controller */ + if (!skb->data_len && tx_ring->last_tx_tso && +- !skb_shinfo(skb)->gso_size) { ++ !skb_is_gso(skb)) { + tx_ring->last_tx_tso = 0; + size -= 4; + } +@@ -2934,8 +2934,7 @@ e1000_xmit_frame(struct sk_buff *skb, st + + #ifdef NETIF_F_TSO + /* Controller Erratum workaround */ +- if (!skb->data_len && tx_ring->last_tx_tso && +- !skb_shinfo(skb)->gso_size) ++ if (!skb->data_len && tx_ring->last_tx_tso && !skb_is_gso(skb)) + count++; + #endif + +diff -urp a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c +--- a/drivers/net/forcedeth.c 2006-07-25 14:41:00.912506734 +0100 ++++ b/drivers/net/forcedeth.c 2006-07-25 14:36:00.295560669 +0100 +@@ -1105,7 +1105,7 @@ static int nv_start_xmit(struct sk_buff + np->tx_skbuff[nr] = skb; + + #ifdef NETIF_F_TSO +- if (skb_shinfo(skb)->gso_size) ++ if (skb_is_gso(skb)) + tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT); + else + #endif +diff -urp a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c +--- a/drivers/net/ixgb/ixgb_main.c 2006-07-25 14:41:00.915506397 +0100 ++++ b/drivers/net/ixgb/ixgb_main.c 2006-07-25 14:36:00.298560355 +0100 +@@ -1163,7 +1163,7 @@ ixgb_tso(struct ixgb_adapter *adapter, s + uint16_t ipcse, tucse, mss; + int err; + +- if(likely(skb_shinfo(skb)->gso_size)) { ++ if (likely(skb_is_gso(skb))) { + if (skb_header_cloned(skb)) { + err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); + if (err) +diff -urp a/drivers/net/loopback.c b/drivers/net/loopback.c +--- a/drivers/net/loopback.c 2006-07-25 14:41:00.915506397 +0100 ++++ b/drivers/net/loopback.c 2006-07-25 14:36:00.298560355 +0100 +@@ -139,7 +139,7 @@ static int loopback_xmit(struct sk_buff + #endif + + #ifdef LOOPBACK_TSO +- if (skb_shinfo(skb)->gso_size) { ++ if (skb_is_gso(skb)) { + BUG_ON(skb->protocol != htons(ETH_P_IP)); + BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP); + +diff -urp a/drivers/net/sky2.c b/drivers/net/sky2.c +--- a/drivers/net/sky2.c 2006-07-25 14:41:00.924505388 +0100 ++++ b/drivers/net/sky2.c 2006-07-25 14:36:00.306559519 +0100 +@@ -1125,7 +1125,7 @@ static unsigned tx_le_req(const struct s + count = sizeof(dma_addr_t) / sizeof(u32); + count += skb_shinfo(skb)->nr_frags * count; + +- if (skb_shinfo(skb)->gso_size) ++ if (skb_is_gso(skb)) + ++count; + + if (skb->ip_summed == CHECKSUM_HW) +diff -urp a/drivers/net/typhoon.c b/drivers/net/typhoon.c +--- a/drivers/net/typhoon.c 2006-07-25 14:41:00.931504603 +0100 ++++ b/drivers/net/typhoon.c 2006-07-25 14:36:00.314558683 +0100 +@@ -805,7 +805,7 @@ typhoon_start_tx(struct sk_buff *skb, st + * If problems develop with TSO, check this first. + */ + numDesc = skb_shinfo(skb)->nr_frags + 1; +- if(skb_tso_size(skb)) ++ if (skb_is_gso(skb)) + numDesc++; + + /* When checking for free space in the ring, we need to also +@@ -845,7 +845,7 @@ typhoon_start_tx(struct sk_buff *skb, st + TYPHOON_TX_PF_VLAN_TAG_SHIFT); + } + +- if(skb_tso_size(skb)) { ++ if (skb_is_gso(skb)) { + first_txd->processFlags |= TYPHOON_TX_PF_TCP_SEGMENT; + first_txd->numDesc++; + +diff -urp a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c +--- a/drivers/s390/net/qeth_main.c 2006-07-25 14:41:00.939503705 +0100 ++++ b/drivers/s390/net/qeth_main.c 2006-07-25 14:36:00.321557952 +0100 +@@ -4454,7 +4454,7 @@ qeth_send_packet(struct qeth_card *card, + queue = card->qdio.out_qs + [qeth_get_priority_queue(card, skb, ipv, cast_type)]; + +- if (skb_shinfo(skb)->gso_size) ++ if (skb_is_gso(skb)) + large_send = card->options.large_send; + + /*are we able to do TSO ? If so ,prepare and send it from here */ +@@ -4501,8 +4501,7 @@ qeth_send_packet(struct qeth_card *card, + card->stats.tx_packets++; + card->stats.tx_bytes += skb->len; + #ifdef CONFIG_QETH_PERF_STATS +- if (skb_shinfo(skb)->gso_size && +- !(large_send == QETH_LARGE_SEND_NO)) { ++ if (skb_is_gso(skb) && !(large_send == QETH_LARGE_SEND_NO)) { + card->perf_stats.large_send_bytes += skb->len; + card->perf_stats.large_send_cnt++; + } +diff -urp a/include/linux/netdevice.h b/include/linux/netdevice.h +--- a/include/linux/netdevice.h 2006-07-25 14:41:00.940503593 +0100 ++++ b/include/linux/netdevice.h 2006-07-25 14:36:00.323557743 +0100 +@@ -541,6 +541,7 @@ struct packet_type { + struct net_device *); + struct sk_buff *(*gso_segment)(struct sk_buff *skb, + int features); ++ int (*gso_send_check)(struct sk_buff *skb); + void *af_packet_priv; + struct list_head list; + }; +@@ -1001,14 +1002,15 @@ extern void linkwatch_run_queue(void); + + static inline int skb_gso_ok(struct sk_buff *skb, int features) + { +- int feature = skb_shinfo(skb)->gso_size ? +- skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT : 0; ++ int feature = skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT; + return (features & feature) == feature; + } + + static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb) + { +- return !skb_gso_ok(skb, dev->features); ++ return skb_is_gso(skb) && ++ (!skb_gso_ok(skb, dev->features) || ++ unlikely(skb->ip_summed != CHECKSUM_HW)); + } + + #endif /* __KERNEL__ */ +diff -urp a/include/linux/skbuff.h b/include/linux/skbuff.h +--- a/include/linux/skbuff.h 2006-07-25 14:41:00.941503481 +0100 ++++ b/include/linux/skbuff.h 2006-07-25 14:36:00.323557743 +0100 +@@ -1403,5 +1403,10 @@ static inline void nf_bridge_get(struct + static inline void nf_reset(struct sk_buff *skb) {} + #endif /* CONFIG_NETFILTER */ + ++static inline int skb_is_gso(const struct sk_buff *skb) ++{ ++ return skb_shinfo(skb)->gso_size; ++} ++ + #endif /* __KERNEL__ */ + #endif /* _LINUX_SKBUFF_H */ +diff -urp a/include/net/protocol.h b/include/net/protocol.h +--- a/include/net/protocol.h 2006-07-25 14:41:00.942503369 +0100 ++++ b/include/net/protocol.h 2006-07-25 14:36:00.324557639 +0100 +@@ -37,6 +37,7 @@ + struct net_protocol { + int (*handler)(struct sk_buff *skb); + void (*err_handler)(struct sk_buff *skb, u32 info); ++ int (*gso_send_check)(struct sk_buff *skb); + struct sk_buff *(*gso_segment)(struct sk_buff *skb, + int features); + int no_policy; +diff -urp a/include/net/tcp.h b/include/net/tcp.h +--- a/include/net/tcp.h 2006-07-25 14:41:00.943503256 +0100 ++++ b/include/net/tcp.h 2006-07-25 14:36:00.325557534 +0100 +@@ -1063,6 +1063,7 @@ extern struct request_sock_ops tcp_reque + + extern int tcp_v4_destroy_sock(struct sock *sk); + ++extern int tcp_v4_gso_send_check(struct sk_buff *skb); + extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features); + + #ifdef CONFIG_PROC_FS +diff -urp a/net/bridge/br_forward.c b/net/bridge/br_forward.c +--- a/net/bridge/br_forward.c 2006-07-25 14:41:00.944503144 +0100 ++++ b/net/bridge/br_forward.c 2006-07-25 14:36:00.326557430 +0100 +@@ -32,7 +32,7 @@ static inline int should_deliver(const s + int br_dev_queue_push_xmit(struct sk_buff *skb) + { + /* drop mtu oversized packets except tso */ +- if (skb->len > skb->dev->mtu && !skb_shinfo(skb)->gso_size) ++ if (skb->len > skb->dev->mtu && !skb_is_gso(skb)) + kfree_skb(skb); + else { + #ifdef CONFIG_BRIDGE_NETFILTER +diff -urp a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c +--- a/net/bridge/br_netfilter.c 2006-07-25 14:41:00.945503032 +0100 ++++ b/net/bridge/br_netfilter.c 2006-07-25 14:36:00.327557325 +0100 +@@ -743,7 +743,7 @@ static int br_nf_dev_queue_xmit(struct s + { + if (skb->protocol == htons(ETH_P_IP) && + skb->len > skb->dev->mtu && +- !skb_shinfo(skb)->gso_size) ++ !skb_is_gso(skb)) + return ip_fragment(skb, br_dev_queue_push_xmit); + else + return br_dev_queue_push_xmit(skb); +diff -urp a/net/core/dev.c b/net/core/dev.c +--- a/net/core/dev.c 2006-07-25 14:41:00.947502808 +0100 ++++ b/net/core/dev.c 2006-07-25 14:36:00.329557116 +0100 +@@ -1083,9 +1083,17 @@ int skb_checksum_help(struct sk_buff *sk + unsigned int csum; + int ret = 0, offset = skb->h.raw - skb->data; + +- if (inward) { +- skb->ip_summed = CHECKSUM_NONE; +- goto out; ++ if (inward) ++ goto out_set_summed; ++ ++ if (unlikely(skb_shinfo(skb)->gso_size)) { ++ static int warned; ++ ++ WARN_ON(!warned); ++ warned = 1; ++ ++ /* Let GSO fix up the checksum. */ ++ goto out_set_summed; + } + + if (skb_cloned(skb)) { +@@ -1102,6 +1110,8 @@ int skb_checksum_help(struct sk_buff *sk + BUG_ON(skb->csum + 2 > offset); + + *(u16*)(skb->h.raw + skb->csum) = csum_fold(csum); ++ ++out_set_summed: + skb->ip_summed = CHECKSUM_NONE; + out: + return ret; +@@ -1122,17 +1132,35 @@ struct sk_buff *skb_gso_segment(struct s + struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); + struct packet_type *ptype; + int type = skb->protocol; ++ int err; + + BUG_ON(skb_shinfo(skb)->frag_list); +- BUG_ON(skb->ip_summed != CHECKSUM_HW); + + skb->mac.raw = skb->data; + skb->mac_len = skb->nh.raw - skb->data; + __skb_pull(skb, skb->mac_len); + ++ if (unlikely(skb->ip_summed != CHECKSUM_HW)) { ++ static int warned; ++ ++ WARN_ON(!warned); ++ warned = 1; ++ ++ if (skb_header_cloned(skb) && ++ (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) ++ return ERR_PTR(err); ++ } ++ + rcu_read_lock(); + list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) { + if (ptype->type == type && !ptype->dev && ptype->gso_segment) { ++ if (unlikely(skb->ip_summed != CHECKSUM_HW)) { ++ err = ptype->gso_send_check(skb); ++ segs = ERR_PTR(err); ++ if (err || skb_gso_ok(skb, features)) ++ break; ++ __skb_push(skb, skb->data - skb->nh.raw); ++ } + segs = ptype->gso_segment(skb, features); + break; + } +diff -urp a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c +--- a/net/ipv4/af_inet.c 2006-07-25 14:41:00.952502247 +0100 ++++ b/net/ipv4/af_inet.c 2006-07-25 14:36:00.334556594 +0100 +@@ -1085,6 +1085,40 @@ int inet_sk_rebuild_header(struct sock * + + EXPORT_SYMBOL(inet_sk_rebuild_header); + ++static int inet_gso_send_check(struct sk_buff *skb) ++{ ++ struct iphdr *iph; ++ struct net_protocol *ops; ++ int proto; ++ int ihl; ++ int err = -EINVAL; ++ ++ if (unlikely(!pskb_may_pull(skb, sizeof(*iph)))) ++ goto out; ++ ++ iph = skb->nh.iph; ++ ihl = iph->ihl * 4; ++ if (ihl < sizeof(*iph)) ++ goto out; ++ ++ if (unlikely(!pskb_may_pull(skb, ihl))) ++ goto out; ++ ++ skb->h.raw = __skb_pull(skb, ihl); ++ iph = skb->nh.iph; ++ proto = iph->protocol & (MAX_INET_PROTOS - 1); ++ err = -EPROTONOSUPPORT; ++ ++ rcu_read_lock(); ++ ops = rcu_dereference(inet_protos[proto]); ++ if (likely(ops && ops->gso_send_check)) ++ err = ops->gso_send_check(skb); ++ rcu_read_unlock(); ++ ++out: ++ return err; ++} ++ + static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features) + { + struct sk_buff *segs = ERR_PTR(-EINVAL); +@@ -1142,6 +1176,7 @@ static struct net_protocol igmp_protocol + static struct net_protocol tcp_protocol = { + .handler = tcp_v4_rcv, + .err_handler = tcp_v4_err, ++ .gso_send_check = tcp_v4_gso_send_check, + .gso_segment = tcp_tso_segment, + .no_policy = 1, + }; +@@ -1188,6 +1223,7 @@ static int ipv4_proc_init(void); + static struct packet_type ip_packet_type = { + .type = __constant_htons(ETH_P_IP), + .func = ip_rcv, ++ .gso_send_check = inet_gso_send_check, + .gso_segment = inet_gso_segment, + }; + +diff -urp a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c +--- a/net/ipv4/ip_output.c 2006-07-25 14:41:00.953502135 +0100 ++++ b/net/ipv4/ip_output.c 2006-07-25 14:36:00.335556489 +0100 +@@ -210,7 +210,7 @@ static inline int ip_finish_output(struc + return dst_output(skb); + } + #endif +- if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) ++ if (skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb)) + return ip_fragment(skb, ip_finish_output2); + else + return ip_finish_output2(skb); +@@ -1095,7 +1095,7 @@ ssize_t ip_append_page(struct sock *sk, + while (size > 0) { + int i; + +- if (skb_shinfo(skb)->gso_size) ++ if (skb_is_gso(skb)) + len = size; + else { + +diff -urp a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c +--- a/net/ipv4/tcp_ipv4.c 2006-07-25 14:39:15.985080788 +0100 ++++ b/net/ipv4/tcp_ipv4.c 2006-07-25 14:36:00.339556071 +0100 +@@ -495,6 +495,24 @@ void tcp_v4_send_check(struct sock *sk, + } + } + ++int tcp_v4_gso_send_check(struct sk_buff *skb) ++{ ++ struct iphdr *iph; ++ struct tcphdr *th; ++ ++ if (!pskb_may_pull(skb, sizeof(*th))) ++ return -EINVAL; ++ ++ iph = skb->nh.iph; ++ th = skb->h.th; ++ ++ th->check = 0; ++ th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0); ++ skb->csum = offsetof(struct tcphdr, check); ++ skb->ip_summed = CHECKSUM_HW; ++ return 0; ++} ++ + /* + * This routine will send an RST to the other tcp. + * +diff -urp a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c +--- a/net/ipv4/xfrm4_output.c 2006-07-25 14:41:00.958501574 +0100 ++++ b/net/ipv4/xfrm4_output.c 2006-07-25 14:36:00.341555862 +0100 +@@ -189,7 +189,7 @@ static int xfrm4_output_finish(struct sk + } + #endif + +- if (!skb_shinfo(skb)->gso_size) ++ if (!skb_is_gso(skb)) + return xfrm4_output_finish2(skb); + + skb->protocol = htons(ETH_P_IP); +diff -urp a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +--- a/net/ipv6/ip6_output.c 2006-07-25 14:41:00.959501461 +0100 ++++ b/net/ipv6/ip6_output.c 2006-07-25 14:36:00.341555862 +0100 +@@ -147,7 +147,7 @@ static int ip6_output2(struct sk_buff *s + + int ip6_output(struct sk_buff *skb) + { +- if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) || ++ if ((skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb)) || + dst_allfrag(skb->dst)) + return ip6_fragment(skb, ip6_output2); + else +diff -urp a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c +--- a/net/ipv6/xfrm6_output.c 2006-07-25 14:41:00.960501349 +0100 ++++ b/net/ipv6/xfrm6_output.c 2006-07-25 14:36:00.342555758 +0100 +@@ -179,7 +179,7 @@ static int xfrm6_output_finish(struct sk + { + struct sk_buff *segs; + +- if (!skb_shinfo(skb)->gso_size) ++ if (!skb_is_gso(skb)) + return xfrm6_output_finish2(skb); + + skb->protocol = htons(ETH_P_IP); |