Netdev List
 help / color / mirror / Atom feed
* [PATCH] : bug fix in multipath drr code.
From: pravin @ 2005-05-23 12:26 UTC (permalink / raw)
  To: netdev; +Cc: David S. Miller, Herbert Xu

[-- Attachment #1: Type: text/plain, Size: 786 bytes --]

hi
  AFAIU, there is a race condition in multipath_drr code,
these code paths try to access & change last_selection variable
without any synchronization.

Please correct me if I am wrong.

Code Path - 1

__ip_route_output_key(...)
{
   ...
   calls drr_select_route
       if(FLOWI_FLAG_MULTIPATHOLDROUTE set){
           check last_selection.
           return  last_selection //so it can return NULL  pointer
       }
   ....
}

Code Path - 2  

rt_secret_rebuild()
{
.....
rt_run_flush(..);
      ->rt_free(rth);
              -> multipath_remove(rt)
                      ->drr_remove()
                              reset last_selection.
....
}

Attached patch also fixes bug in function drr_init ::
multipath_alg_register(..) is called with wrong algorithm ID.


Regards
Pravin.


[-- Attachment #2: multipath-last_selection-race-fix.patch --]
[-- Type: text/x-patch, Size: 1913 bytes --]

Signed-off by: Pravin B. Shelar <pravins@calsoftinc.com>

Index: linux-2.6.12-rc4/net/ipv4/multipath_drr.c
===================================================================
--- linux-2.6.12-rc4.orig/net/ipv4/multipath_drr.c	2005-05-06 22:20:31.000000000 -0700
+++ linux-2.6.12-rc4/net/ipv4/multipath_drr.c	2005-05-22 06:41:39.000000000 -0700
@@ -145,11 +145,13 @@
 	int cur_min_devidx = -1;
 
        	/* if necessary and possible utilize the old alternative */
-	if ((flp->flags & FLOWI_FLAG_MULTIPATHOLDROUTE) != 0 &&
-	    last_selection != NULL) {
-		result = last_selection;
-		*rp = result;
-		return;
+	if ((flp->flags & FLOWI_FLAG_MULTIPATHOLDROUTE) != 0 ) {
+		struct rtable *last_result = last_selection;
+		if(last_result != NULL &&
+		   multipath_comparekeys(&last_result->fl, flp)) {
+			*rp = last_result;
+			return;
+		}
 	}
 
 	/* 1. make sure all alt. nexthops have the same GC related data */
@@ -244,7 +246,7 @@
 	if (err)
 		return err;
 
-	err = multipath_alg_register(&drr_ops, IP_MP_ALG_RR);
+	err = multipath_alg_register(&drr_ops, IP_MP_ALG_DRR);
 	if (err)
 		goto fail;
 
Index: linux-2.6.12-rc4/net/ipv4/multipath_rr.c
===================================================================
--- linux-2.6.12-rc4.orig/net/ipv4/multipath_rr.c	2005-05-06 22:20:31.000000000 -0700
+++ linux-2.6.12-rc4/net/ipv4/multipath_rr.c	2005-05-22 06:41:20.000000000 -0700
@@ -64,10 +64,13 @@
 	int min_use = -1;
 
 	/* if necessary and possible utilize the old alternative */
-	if ((flp->flags & FLOWI_FLAG_MULTIPATHOLDROUTE) != 0 &&
-	    last_used != NULL) {
-		result = last_used;
-		goto out;
+	if ((flp->flags & FLOWI_FLAG_MULTIPATHOLDROUTE) != 0 ) {
+		struct rtable *last_result = last_used;
+		if(last_result != NULL &&
+		   multipath_comparekeys(&last_result->fl, flp)) {
+			result = last_result;
+			goto out;
+		}
 	}
 
 	/* 1. make sure all alt. nexthops have the same GC related data

^ permalink raw reply

* Re: Why /sys/class/net/*/features is read-only?
From: Stephen Hemminger @ 2005-05-23 16:28 UTC (permalink / raw)
  To: Catalin(ux aka Dino) BOIE; +Cc: netdev
In-Reply-To: <Pine.LNX.4.62.0505201346420.29305@webhosting.rdsbv.ro>

On Mon, 23 May 2005 10:46:50 +0300 (EEST)
"Catalin(ux aka Dino) BOIE" <util@deuroconsult.ro> wrote:

> Hello!
> 
> Why features file is read-only. If an admin want to force some attributes, 
> we can let them, right?
>

Leave it read-only because the hardware may not want to allow them on that flavor and so it would
have to be device specific.

^ permalink raw reply

* Re: [PATCH] Implement NETDEV_FEAT_CHANGE
From: Stephen Hemminger @ 2005-05-23 16:33 UTC (permalink / raw)
  To: Catalin(ux aka Dino) BOIE; +Cc: netdev, davem
In-Reply-To: <Pine.LNX.4.62.0505201527250.26127@webhosting.rdsbv.ro>


> --- notify1/net/core/ethtool.c	2005-03-02 09:38:37.000000000 +0200
> +++ linux/net/core/ethtool.c	2005-05-23 11:30:47.000000000 +0300
...
> @@ -712,7 +715,6 @@ int dev_ethtool(struct ifreq *ifr)
>  		break;
>  	case ETHTOOL_GDRVINFO:
>  		rc = ethtool_get_drvinfo(dev, useraddr);
> -
>  		break;

White space creep

>  	case ETHTOOL_GREGS:
>  		rc = ethtool_get_regs(dev, useraddr);
> @@ -801,6 +803,10 @@ int dev_ethtool(struct ifreq *ifr)
>  	
>  	if(dev->ethtool_ops->complete)
>  		dev->ethtool_ops->complete(dev);
> +
> +	if (old_features != dev->features)
> +		netdev_features_change(dev);
> +
>  	return rc;
>  
>   ioctl:

Did you check for any  drivers that don't use ethtool_ops?

^ permalink raw reply

* Re: [Netem] [PATCH] (3/3) netem: allow random reordering
From: Stephen Hemminger @ 2005-05-23 17:25 UTC (permalink / raw)
  To: Julio Kriger; +Cc: David S. Miller, netdev, netem
In-Reply-To: <682bc30a050520132819b66fee@mail.gmail.com>

On Fri, 20 May 2005 20:28:40 +0000
Julio Kriger <juliokriger@gmail.com> wrote:

> Hi!
> How do I use this feature? Shouldn't tc be modified to accept this new feature?
> Regards,
> 
> Julio

Use this (it will be in the next version of iproute2).
Also, you need to specify a delay because that is how netem does the reordering.

diff -X dontdiff -urN iproute2-2.6.11-050330/include/linux/pkt_sched.h iproute2-netem/include/linux/pkt_sched.h
--- iproute2-2.6.11-050330/include/linux/pkt_sched.h	2005-04-01 11:58:11.000000000 -0800
+++ iproute2-netem/include/linux/pkt_sched.h	2005-05-04 11:31:14.000000000 -0700
@@ -427,6 +427,7 @@
 	TCA_NETEM_UNSPEC,
 	TCA_NETEM_CORR,
 	TCA_NETEM_DELAY_DIST,
+	TCA_NETEM_REORDER,
 	__TCA_NETEM_MAX,
 };
 
@@ -437,7 +438,7 @@
 	__u32	latency;	/* added delay (us) */
 	__u32   limit;		/* fifo limit (packets) */
 	__u32	loss;		/* random packet loss (0=none ~0=100%) */
-	__u32	gap;		/* re-ordering gap (0 for delay all) */
+	__u32	gap;		/* re-ordering gap (0 for none) */
 	__u32   duplicate;	/* random packet dup  (0=none ~0=100%) */
 	__u32	jitter;		/* random jitter in latency (us) */
 };
@@ -449,6 +450,12 @@
 	__u32	dup_corr;	/* duplicate correlation  */
 };
 
+struct tc_netem_reorder
+{
+	__u32	probability;
+	__u32	correlation;
+};
+
 #define NETEM_DIST_SCALE	8192
 
 #endif
diff -X dontdiff -urN iproute2-2.6.11-050330/tc/q_netem.c iproute2-netem/tc/q_netem.c
--- iproute2-2.6.11-050330/tc/q_netem.c	2005-04-01 11:58:11.000000000 -0800
+++ iproute2-netem/tc/q_netem.c	2005-05-04 13:31:25.000000000 -0700
@@ -29,11 +29,11 @@
 {
 	fprintf(stderr, 
 "Usage: ... netem [ limit PACKETS ] \n" \
-"		  [ delay TIME [ JITTER [CORRELATION]]]\n" \
+"                 [ delay TIME [ JITTER [CORRELATION]]]\n" \
+"                 [ distribution {uniform|normal|pareto|paretonormal} ]\n" \
 "                 [ drop PERCENT [CORRELATION]] \n" \
 "                 [ duplicate PERCENT [CORRELATION]]\n" \
-"		  [ distribution {uniform|normal|pareto|paretonormal} ]\n" \
-"                 [ gap PACKETS ]\n");
+"                 [ reorder PRECENT [CORRELATION] [ gap DISTANCE ]]\n");
 }
 
 static void explain1(const char *arg)
@@ -127,11 +127,13 @@
 	struct rtattr *tail;
 	struct tc_netem_qopt opt;
 	struct tc_netem_corr cor;
+	struct tc_netem_reorder reorder;
 	__s16 dist_data[MAXDIST];
 
 	memset(&opt, 0, sizeof(opt));
 	opt.limit = 1000;
 	memset(&cor, 0, sizeof(cor));
+	memset(&reorder, 0, sizeof(reorder));
 
 	while (argc > 0) {
 		if (matches(*argv, "limit") == 0) {
@@ -178,6 +180,19 @@
 					return -1;
 				}
 			}
+		} else if (matches(*argv, "reorder") == 0) {
+			NEXT_ARG();
+			if (get_percent(&reorder.probability, *argv)) {
+				explain1("reorder");
+				return -1;
+			}
+			if (NEXT_IS_NUMBER()) {
+				NEXT_ARG();
+				if (get_percent(&reorder.correlation, *argv)) {
+					explain1("reorder");
+					return -1;
+				}
+			}
 		} else if (matches(*argv, "gap") == 0) {
 			NEXT_ARG();
 			if (get_u32(&opt.gap, *argv, 0)) {
@@ -215,8 +230,27 @@
 
 	tail = NLMSG_TAIL(n);
 
+	if (reorder.probability) {
+		if (opt.latency == 0) {
+			fprintf(stderr, "reordering not possible without specifying some delay\n");
+		}
+		if (opt.gap == 0)
+			opt.gap = 1;
+	} else if (opt.gap > 0) {
+		fprintf(stderr, "gap specified without reorder probability\n");
+		explain();
+		return -1;
+	}
+
+	if (dist_size > 0 && (opt.latency == 0 || opt.jitter == 0)) {
+		fprintf(stderr, "distribution specified but no latency and jitter values\n");
+		explain();
+		return -1;
+	}
+
 	addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
 	addattr_l(n, 1024, TCA_NETEM_CORR, &cor, sizeof(cor));
+	addattr_l(n, 1024, TCA_NETEM_REORDER, &reorder, sizeof(reorder));
 
 	if (dist_size > 0) {
 		addattr_l(n, 32768, TCA_NETEM_DELAY_DIST,
@@ -229,6 +263,7 @@
 static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 {
 	const struct tc_netem_corr *cor = NULL;
+	const struct tc_netem_reorder *reorder = NULL;
 	struct tc_netem_qopt qopt;
 	int len = RTA_PAYLOAD(opt) - sizeof(qopt);
 	SPRINT_BUF(b1);
@@ -252,6 +287,11 @@
 				return -1;
 			cor = RTA_DATA(tb[TCA_NETEM_CORR]);
 		}
+		if (tb[TCA_NETEM_REORDER]) {
+			if (RTA_PAYLOAD(tb[TCA_NETEM_REORDER]) < sizeof(*reorder))
+				return -1;
+			reorder = RTA_DATA(tb[TCA_NETEM_REORDER]);
+		}
 	}
 
 	fprintf(f, "limit %d", qopt.limit);
@@ -278,10 +318,19 @@
 		if (cor && cor->dup_corr)
 			fprintf(f, " %s", sprint_percent(cor->dup_corr, b1));
 	}
+			
+	if (reorder && reorder->probability) {
+		fprintf(f, " reorder %s", 
+			sprint_percent(reorder->probability, b1));
+		if (reorder->correlation)
+			fprintf(f, " %s", 
+				sprint_percent(reorder->correlation, b1));
+	}
 
 	if (qopt.gap)
 		fprintf(f, " gap %lu", (unsigned long)qopt.gap);
 
+
 	return 0;
 }
 

^ permalink raw reply

* [PATCH] netem: fix logic bug in reorder conditional
From: Stephen Hemminger @ 2005-05-23 17:43 UTC (permalink / raw)
  To: Julio Kriger; +Cc: David S. Miller, netdev, netem
In-Reply-To: <682bc30a05052116005bc813a2@mail.gmail.com>

Thanks, Julio you spotted the problem with the logic.  This should fix it:

Index: netem-2.6.12-rc4/net/sched/sch_netem.c
===================================================================
--- netem-2.6.12-rc4.orig/net/sched/sch_netem.c
+++ netem-2.6.12-rc4/net/sched/sch_netem.c
@@ -181,13 +181,9 @@ static int netem_enqueue(struct sk_buff 
 		q->duplicate = dupsave;
 	}
 
-	/* 
-	 * Do re-ordering by putting one out of N packets at the front
-	 * of the queue.
-	 * gap == 0 is special case for no-reordering.
-	 */
-	if (q->gap == 0 && q->counter < q->gap && 
-	    q->reorder < get_crandom(&q->reorder_cor)) {
+	if (q->gap == 0 		/* not doing reordering */
+	    || q->counter < q->gap 	/* inside last reordering gap */
+	    || q->reorder < get_crandom(&q->reorder_cor)) {
 		psched_time_t now;
 		PSCHED_GET_TIME(now);
 		PSCHED_TADD2(now, tabledist(q->latency, q->jitter, 
@@ -196,6 +192,10 @@ static int netem_enqueue(struct sk_buff 
 		++q->counter;
 		ret = q->qdisc->enqueue(skb, q->qdisc);
 	} else {
+		/* 
+		 * Do re-ordering by putting one out of N packets at the front
+		 * of the queue.
+		 */
 		PSCHED_GET_TIME(cb->time_to_send);
 		q->counter = 0;
 		ret = q->qdisc->ops->requeue(skb, q->qdisc);

^ permalink raw reply

* Re: [PATCH] Super TSO v2
From: David S. Miller @ 2005-05-23 18:43 UTC (permalink / raw)
  To: herbert; +Cc: netdev
In-Reply-To: <20050523095417.GA18770@gondor.apana.org.au>

From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Mon, 23 May 2005 19:54:17 +1000

> Perhaps we should set the goal based on the cwnd as we do now?
> 
> As it is I believe we may be doing more work compared to the
> status quo because it's always building 64K blocks and then
> cutting them up as dictated by the cwnd.  On the other hand, the
> current code simply builds the packets up to the size that cwnd
> allows.

I played with this, and it makes no difference.

It would only help when:

1) we are building sk->sk_send_head, and
2) sk->sk_send_head is the tail of the write queue

But the SKB splitting is so cheap that it doesn't
show up.

And if we sleep or defer for some reason, say while copying the data
from userspace or whatever, all of this information changes and we
don't bunch up as much as we could have.

Also, in my current code we defer sending not just at ACK arrive
processing, but also when doing normal sends from sendmsg() and
sendpages().  Which totally invalidates your suggested scheme :-)

^ permalink raw reply

* Re: [PATCH] [BRIDGE] Set features based on slave's ones (was Ethernet Bridging: Enable Hardware Checksumming)
From: Jon Mason @ 2005-05-23 19:14 UTC (permalink / raw)
  To: Catalin(ux aka Dino) BOIE; +Cc: netdev, davem
In-Reply-To: <Pine.LNX.4.62.0505231226160.20838@webhosting.rdsbv.ro>

> The code applies the ~ first, then the | and _then_ the &.
> If we have:
> a &= a | ~b;
> it is equivalent with:
> a = a & (a | ~b);

 Ah, that is what I was missing.  Sorry.

^ permalink raw reply

* [PATCH] Super TSO v3
From: David S. Miller @ 2005-05-23 19:19 UTC (permalink / raw)
  To: netdev

[-- Attachment #1: Type: Text/Plain, Size: 1994 bytes --]


Ok, new version.  This weekend has been productive.

I discoevered a performance anomaly with Linux receivers,
cause by enormous stretch ACK generation, which you'll need
to fix if you want to test this patch against Linux receivers.

When we do ucopy receive (ie. copying directly to userspace
during tcp input processing) we attempt to delay the ACK
until cleanup_rbuf() is invoked.  Most of the time this
technique works very well, and we emit one ACK advertising
the largest window.

But this explodes if the ucopy prequeue is large enough.
When the receiver is cpu limited and TSO frames are large,
the receiver is inundated with ucopy processing, such that
the ACK comes out very late.  Often, this is so late that
by the time the sender gets the ACK the window has emptied
too much to be kept full by the sender.

The existing TSO code mostly avoided this by keeping the
TSO packets no larger than 1/8 of the available window.
But with the new code we can get much larger TSO frames.

The other major change now is that we do TSO deferral both
at sendmsg()/sendpage() packet send time, as well as when
processing ACKs to make progress in the write queue.

The guts of the logic is in tcp_tso_should_defer().  And
when dealing with a TSO frame, tcp_write_xmit() calls
this instead of tcp_nagle_test().  So you can view this
deferral as a sort of "TSO Nagle".

In v2, there was some code that checked if in_flight was
non-zero, to make sure we will get some ACKs back, but
that is implicitly handled by the "1/tso_win_divisor"
check.

Potential cleanups are of course still sprinkled all
over.  For example, __tcp_push_pending_frames() and
__tcp_data_snd_check() are basically identical now.

_iff_ you test this code, please make sure the receiver
bug fix is installed on any Linux systems you are using
as the receiver in your testing.  There are three
attachments:

1) the 2.6.12-rcX Super TSO patch v3
2) the 2.6.12.rcX TCP receiver bug fix
3) the 2.4.30 TCP receiver bug fix

Enjoy.

[-- Attachment #2: tcp_super_tso.diff --]
[-- Type: Text/Plain, Size: 38869 bytes --]

--- 1/include/linux/tcp.h.~1~	2005-05-20 22:12:09.000000000 -0700
+++ 2/include/linux/tcp.h	2005-05-20 22:12:22.000000000 -0700
@@ -280,13 +280,15 @@ struct tcp_sock {
 	__u32	snd_wnd;	/* The window we expect to receive	*/
 	__u32	max_window;	/* Maximal window ever seen from peer	*/
 	__u32	pmtu_cookie;	/* Last pmtu seen by socket		*/
-	__u32	mss_cache;	/* Cached effective mss, not including SACKS */
-	__u16	mss_cache_std;	/* Like mss_cache, but without TSO */
+	__u16	mss_cache;	/* Cached effective mss, not including SACKS */
+	__u16	xmit_size_goal;	/* Goal for segmenting output packets	*/
+	__u32	xmit_size_cache;/* Cache for keeping xmit_size_goal uptodate */
 	__u16	ext_header_len;	/* Network protocol overhead (IP/IPv6 options) */
 	__u8	ca_state;	/* State of fast-retransmit machine 	*/
 	__u8	retransmits;	/* Number of unrecovered RTO timeouts.	*/
 
 	__u16	advmss;		/* Advertised MSS			*/
+	__u16	deferred;	/* Packets deferred for segmentation	*/
 	__u32	window_clamp;	/* Maximal window to advertise		*/
 	__u32	rcv_ssthresh;	/* Current window clamp			*/
 
--- 1/include/net/sock.h.~1~	2005-05-20 22:12:09.000000000 -0700
+++ 2/include/net/sock.h	2005-05-20 22:12:22.000000000 -0700
@@ -1130,13 +1130,16 @@ static inline void sk_stream_moderate_sn
 static inline struct sk_buff *sk_stream_alloc_pskb(struct sock *sk,
 						   int size, int mem, int gfp)
 {
-	struct sk_buff *skb = alloc_skb(size + sk->sk_prot->max_header, gfp);
+	struct sk_buff *skb;
+	int hdr_len;
 
+	hdr_len = SKB_DATA_ALIGN(sk->sk_prot->max_header);
+	skb = alloc_skb(size + hdr_len, gfp);
 	if (skb) {
 		skb->truesize += mem;
 		if (sk->sk_forward_alloc >= (int)skb->truesize ||
 		    sk_stream_mem_schedule(sk, skb->truesize, 0)) {
-			skb_reserve(skb, sk->sk_prot->max_header);
+			skb_reserve(skb, hdr_len);
 			return skb;
 		}
 		__kfree_skb(skb);
--- 1/include/net/tcp.h.~1~	2005-05-20 22:12:09.000000000 -0700
+++ 2/include/net/tcp.h	2005-05-22 21:38:48.000000000 -0700
@@ -817,11 +817,18 @@ static inline int tcp_ack_scheduled(stru
 	return tp->ack.pending&TCP_ACK_SCHED;
 }
 
-static __inline__ void tcp_dec_quickack_mode(struct tcp_sock *tp)
+static __inline__ void tcp_dec_quickack_mode(struct tcp_sock *tp, unsigned int pkts)
 {
-	if (tp->ack.quick && --tp->ack.quick == 0) {
-		/* Leaving quickack mode we deflate ATO. */
-		tp->ack.ato = TCP_ATO_MIN;
+	if (tp->ack.quick) {
+		if (pkts > tp->ack.quick)
+			tp->ack.quick = 0;
+		else
+			tp->ack.quick -= pkts;
+
+		if (!tp->ack.quick) {
+			/* Leaving quickack mode we deflate ATO. */
+			tp->ack.ato = TCP_ATO_MIN;
+		}
 	}
 }
 
@@ -939,7 +946,14 @@ extern __u32 cookie_v4_init_sequence(str
 
 /* tcp_output.c */
 
-extern int tcp_write_xmit(struct sock *, int nonagle);
+extern void __tcp_data_snd_check(struct sock *sk, struct sk_buff *skb);
+extern void __tcp_push_pending_frames(struct sock *sk,
+				      struct tcp_sock *tp,
+				      unsigned int cur_mss,
+				      int nonagle);
+extern int tcp_may_send_now(struct sock *sk, struct tcp_sock *tp);
+extern int tcp_tso_mince(struct sock *sk, struct tcp_sock *tp,
+			 struct sk_buff *skb);
 extern int tcp_retransmit_skb(struct sock *, struct sk_buff *);
 extern void tcp_xmit_retransmit_queue(struct sock *);
 extern void tcp_simple_retransmit(struct sock *);
@@ -951,7 +965,7 @@ extern int  tcp_write_wakeup(struct sock
 extern void tcp_send_fin(struct sock *sk);
 extern void tcp_send_active_reset(struct sock *sk, int priority);
 extern int  tcp_send_synack(struct sock *);
-extern void tcp_push_one(struct sock *, unsigned mss_now);
+extern void tcp_push_one(struct sock *, unsigned int mss_now);
 extern void tcp_send_ack(struct sock *sk);
 extern void tcp_send_delayed_ack(struct sock *sk);
 
@@ -1054,7 +1068,7 @@ static inline void tcp_reset_xmit_timer(
 static inline void tcp_initialize_rcv_mss(struct sock *sk)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
-	unsigned int hint = min(tp->advmss, tp->mss_cache_std);
+	unsigned int hint = min(tp->advmss, tp->mss_cache);
 
 	hint = min(hint, tp->rcv_wnd/2);
 	hint = min(hint, TCP_MIN_RCVMSS);
@@ -1353,23 +1367,23 @@ static inline void tcp_cwnd_validate(str
 }
 
 /* Set slow start threshould and cwnd not falling to slow start */
-static inline void __tcp_enter_cwr(struct tcp_sock *tp)
+static inline void __tcp_enter_cwr(struct tcp_sock *tp, unsigned int pkts)
 {
 	tp->undo_marker = 0;
 	tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
 	tp->snd_cwnd = min(tp->snd_cwnd,
-			   tcp_packets_in_flight(tp) + 1U);
+			   tcp_packets_in_flight(tp) + pkts);
 	tp->snd_cwnd_cnt = 0;
 	tp->high_seq = tp->snd_nxt;
 	tp->snd_cwnd_stamp = tcp_time_stamp;
 	TCP_ECN_queue_cwr(tp);
 }
 
-static inline void tcp_enter_cwr(struct tcp_sock *tp)
+static inline void tcp_enter_cwr(struct tcp_sock *tp, unsigned int pkts)
 {
 	tp->prior_ssthresh = 0;
 	if (tp->ca_state < TCP_CA_CWR) {
-		__tcp_enter_cwr(tp);
+		__tcp_enter_cwr(tp, pkts);
 		tcp_set_ca_state(tp, TCP_CA_CWR);
 	}
 }
@@ -1397,74 +1411,6 @@ static __inline__ void tcp_minshall_upda
 		tp->snd_sml = TCP_SKB_CB(skb)->end_seq;
 }
 
-/* Return 0, if packet can be sent now without violation Nagle's rules:
-   1. It is full sized.
-   2. Or it contains FIN.
-   3. Or TCP_NODELAY was set.
-   4. Or TCP_CORK is not set, and all sent packets are ACKed.
-      With Minshall's modification: all sent small packets are ACKed.
- */
-
-static __inline__ int
-tcp_nagle_check(const struct tcp_sock *tp, const struct sk_buff *skb, 
-		unsigned mss_now, int nonagle)
-{
-	return (skb->len < mss_now &&
-		!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) &&
-		((nonagle&TCP_NAGLE_CORK) ||
-		 (!nonagle &&
-		  tp->packets_out &&
-		  tcp_minshall_check(tp))));
-}
-
-extern void tcp_set_skb_tso_segs(struct sock *, struct sk_buff *);
-
-/* This checks if the data bearing packet SKB (usually sk->sk_send_head)
- * should be put on the wire right now.
- */
-static __inline__ int tcp_snd_test(struct sock *sk,
-				   struct sk_buff *skb,
-				   unsigned cur_mss, int nonagle)
-{
-	struct tcp_sock *tp = tcp_sk(sk);
-	int pkts = tcp_skb_pcount(skb);
-
-	if (!pkts) {
-		tcp_set_skb_tso_segs(sk, skb);
-		pkts = tcp_skb_pcount(skb);
-	}
-
-	/*	RFC 1122 - section 4.2.3.4
-	 *
-	 *	We must queue if
-	 *
-	 *	a) The right edge of this frame exceeds the window
-	 *	b) There are packets in flight and we have a small segment
-	 *	   [SWS avoidance and Nagle algorithm]
-	 *	   (part of SWS is done on packetization)
-	 *	   Minshall version sounds: there are no _small_
-	 *	   segments in flight. (tcp_nagle_check)
-	 *	c) We have too many packets 'in flight'
-	 *
-	 * 	Don't use the nagle rule for urgent data (or
-	 *	for the final FIN -DaveM).
-	 *
-	 *	Also, Nagle rule does not apply to frames, which
-	 *	sit in the middle of queue (they have no chances
-	 *	to get new data) and if room at tail of skb is
-	 *	not enough to save something seriously (<32 for now).
-	 */
-
-	/* Don't be strict about the congestion window for the
-	 * final FIN frame.  -DaveM
-	 */
-	return (((nonagle&TCP_NAGLE_PUSH) || tp->urg_mode
-		 || !tcp_nagle_check(tp, skb, cur_mss, nonagle)) &&
-		(((tcp_packets_in_flight(tp) + (pkts-1)) < tp->snd_cwnd) ||
-		 (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)) &&
-		!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una + tp->snd_wnd));
-}
-
 static __inline__ void tcp_check_probe_timer(struct sock *sk, struct tcp_sock *tp)
 {
 	if (!tp->packets_out && !tp->pending)
@@ -1477,42 +1423,12 @@ static __inline__ int tcp_skb_is_last(co
 	return skb->next == (struct sk_buff *)&sk->sk_write_queue;
 }
 
-/* Push out any pending frames which were held back due to
- * TCP_CORK or attempt at coalescing tiny packets.
- * The socket must be locked by the caller.
- */
-static __inline__ void __tcp_push_pending_frames(struct sock *sk,
-						 struct tcp_sock *tp,
-						 unsigned cur_mss,
-						 int nonagle)
-{
-	struct sk_buff *skb = sk->sk_send_head;
-
-	if (skb) {
-		if (!tcp_skb_is_last(sk, skb))
-			nonagle = TCP_NAGLE_PUSH;
-		if (!tcp_snd_test(sk, skb, cur_mss, nonagle) ||
-		    tcp_write_xmit(sk, nonagle))
-			tcp_check_probe_timer(sk, tp);
-	}
-	tcp_cwnd_validate(sk, tp);
-}
-
 static __inline__ void tcp_push_pending_frames(struct sock *sk,
 					       struct tcp_sock *tp)
 {
 	__tcp_push_pending_frames(sk, tp, tcp_current_mss(sk, 1), tp->nonagle);
 }
 
-static __inline__ int tcp_may_send_now(struct sock *sk, struct tcp_sock *tp)
-{
-	struct sk_buff *skb = sk->sk_send_head;
-
-	return (skb &&
-		tcp_snd_test(sk, skb, tcp_current_mss(sk, 1),
-			     tcp_skb_is_last(sk, skb) ? TCP_NAGLE_PUSH : tp->nonagle));
-}
-
 static __inline__ void tcp_init_wl(struct tcp_sock *tp, u32 ack, u32 seq)
 {
 	tp->snd_wl1 = seq;
@@ -1986,7 +1902,7 @@ static inline void tcp_westwood_update_r
 static inline __u32 __tcp_westwood_bw_rttmin(const struct tcp_sock *tp)
 {
         return max((tp->westwood.bw_est) * (tp->westwood.rtt_min) /
-		   (__u32) (tp->mss_cache_std),
+		   (__u32) (tp->mss_cache),
 		   2U);
 }
 
--- 1/net/ipv4/tcp.c.~1~	2005-05-20 22:12:09.000000000 -0700
+++ 2/net/ipv4/tcp.c	2005-05-22 21:39:38.000000000 -0700
@@ -634,7 +634,7 @@ static ssize_t do_tcp_sendpages(struct s
 			 size_t psize, int flags)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
-	int mss_now;
+	int mss_now, size_goal;
 	int err;
 	ssize_t copied;
 	long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
@@ -647,6 +647,7 @@ static ssize_t do_tcp_sendpages(struct s
 	clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
 
 	mss_now = tcp_current_mss(sk, !(flags&MSG_OOB));
+	size_goal = tp->xmit_size_goal;
 	copied = 0;
 
 	err = -EPIPE;
@@ -660,7 +661,7 @@ static ssize_t do_tcp_sendpages(struct s
 		int offset = poffset % PAGE_SIZE;
 		int size = min_t(size_t, psize, PAGE_SIZE - offset);
 
-		if (!sk->sk_send_head || (copy = mss_now - skb->len) <= 0) {
+		if (!sk->sk_send_head || (copy = size_goal - skb->len) <= 0) {
 new_segment:
 			if (!sk_stream_memory_free(sk))
 				goto wait_for_sndbuf;
@@ -671,7 +672,7 @@ new_segment:
 				goto wait_for_memory;
 
 			skb_entail(sk, tp, skb);
-			copy = mss_now;
+			copy = size_goal;
 		}
 
 		if (copy > size)
@@ -712,7 +713,7 @@ new_segment:
 		if (!(psize -= copy))
 			goto out;
 
-		if (skb->len != mss_now || (flags & MSG_OOB))
+		if (skb->len != size_goal || (flags & MSG_OOB))
 			continue;
 
 		if (forced_push(tp)) {
@@ -732,6 +733,7 @@ wait_for_memory:
 			goto do_error;
 
 		mss_now = tcp_current_mss(sk, !(flags&MSG_OOB));
+		size_goal = tp->xmit_size_goal;
 	}
 
 out:
@@ -773,15 +775,11 @@ ssize_t tcp_sendpage(struct socket *sock
 
 static inline int select_size(struct sock *sk, struct tcp_sock *tp)
 {
-	int tmp = tp->mss_cache_std;
+	int tmp = tp->mss_cache;
 
-	if (sk->sk_route_caps & NETIF_F_SG) {
-		int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER);
+	if (sk->sk_route_caps & NETIF_F_SG)
+		tmp = 0;
 
-		if (tmp >= pgbreak &&
-		    tmp <= pgbreak + (MAX_SKB_FRAGS - 1) * PAGE_SIZE)
-			tmp = pgbreak;
-	}
 	return tmp;
 }
 
@@ -792,7 +790,7 @@ int tcp_sendmsg(struct kiocb *iocb, stru
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct sk_buff *skb;
 	int iovlen, flags;
-	int mss_now;
+	int mss_now, size_goal;
 	int err, copied;
 	long timeo;
 
@@ -811,6 +809,7 @@ int tcp_sendmsg(struct kiocb *iocb, stru
 	clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
 
 	mss_now = tcp_current_mss(sk, !(flags&MSG_OOB));
+	size_goal = tp->xmit_size_goal;
 
 	/* Ok commence sending. */
 	iovlen = msg->msg_iovlen;
@@ -833,7 +832,7 @@ int tcp_sendmsg(struct kiocb *iocb, stru
 			skb = sk->sk_write_queue.prev;
 
 			if (!sk->sk_send_head ||
-			    (copy = mss_now - skb->len) <= 0) {
+			    (copy = size_goal - skb->len) <= 0) {
 
 new_segment:
 				/* Allocate new segment. If the interface is SG,
@@ -856,7 +855,7 @@ new_segment:
 					skb->ip_summed = CHECKSUM_HW;
 
 				skb_entail(sk, tp, skb);
-				copy = mss_now;
+				copy = size_goal;
 			}
 
 			/* Try to append data to the end of skb. */
@@ -891,11 +890,6 @@ new_segment:
 					tcp_mark_push(tp, skb);
 					goto new_segment;
 				} else if (page) {
-					/* If page is cached, align
-					 * offset to L1 cache boundary
-					 */
-					off = (off + L1_CACHE_BYTES - 1) &
-					      ~(L1_CACHE_BYTES - 1);
 					if (off == PAGE_SIZE) {
 						put_page(page);
 						TCP_PAGE(sk) = page = NULL;
@@ -956,7 +950,7 @@ new_segment:
 			if ((seglen -= copy) == 0 && iovlen == 0)
 				goto out;
 
-			if (skb->len != mss_now || (flags & MSG_OOB))
+			if (skb->len != size_goal || (flags & MSG_OOB))
 				continue;
 
 			if (forced_push(tp)) {
@@ -976,6 +970,7 @@ wait_for_memory:
 				goto do_error;
 
 			mss_now = tcp_current_mss(sk, !(flags&MSG_OOB));
+			size_goal = tp->xmit_size_goal;
 		}
 	}
 
@@ -2135,7 +2130,7 @@ void tcp_get_info(struct sock *sk, struc
 
 	info->tcpi_rto = jiffies_to_usecs(tp->rto);
 	info->tcpi_ato = jiffies_to_usecs(tp->ack.ato);
-	info->tcpi_snd_mss = tp->mss_cache_std;
+	info->tcpi_snd_mss = tp->mss_cache;
 	info->tcpi_rcv_mss = tp->ack.rcv_mss;
 
 	info->tcpi_unacked = tp->packets_out;
@@ -2185,7 +2180,7 @@ int tcp_getsockopt(struct sock *sk, int 
 
 	switch (optname) {
 	case TCP_MAXSEG:
-		val = tp->mss_cache_std;
+		val = tp->mss_cache;
 		if (!val && ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)))
 			val = tp->rx_opt.user_mss;
 		break;
--- 1/net/ipv4/tcp_input.c.~1~	2005-05-20 22:12:09.000000000 -0700
+++ 2/net/ipv4/tcp_input.c	2005-05-23 11:53:05.000000000 -0700
@@ -805,10 +805,10 @@ __u32 tcp_init_cwnd(struct tcp_sock *tp,
 	__u32 cwnd = (dst ? dst_metric(dst, RTAX_INITCWND) : 0);
 
 	if (!cwnd) {
-		if (tp->mss_cache_std > 1460)
+		if (tp->mss_cache > 1460)
 			cwnd = 2;
 		else
-			cwnd = (tp->mss_cache_std > 1095) ? 3 : 4;
+			cwnd = (tp->mss_cache > 1095) ? 3 : 4;
 	}
 	return min_t(__u32, cwnd, tp->snd_cwnd_clamp);
 }
@@ -974,14 +974,6 @@ tcp_sacktag_write_queue(struct sock *sk,
 	int flag = 0;
 	int i;
 
-	/* So, SACKs for already sent large segments will be lost.
-	 * Not good, but alternative is to resegment the queue. */
-	if (sk->sk_route_caps & NETIF_F_TSO) {
-		sk->sk_route_caps &= ~NETIF_F_TSO;
-		sock_set_flag(sk, SOCK_NO_LARGESEND);
-		tp->mss_cache = tp->mss_cache_std;
-	}
-
 	if (!tp->sacked_out)
 		tp->fackets_out = 0;
 	prior_fackets = tp->fackets_out;
@@ -1038,6 +1030,15 @@ tcp_sacktag_write_queue(struct sock *sk,
 			if(!before(TCP_SKB_CB(skb)->seq, end_seq))
 				break;
 
+			/* Even if mincing a TSO frame fails, we
+			 * continue anyways.  We will end up with
+			 * more coarse SACK information, but it is
+			 * better than ignoring all the SACK information
+			 * altogether.
+			 */
+			if (tcp_skb_pcount(skb) > 1)
+				tcp_tso_mince(sk, tp, skb);
+
 			fack_count += tcp_skb_pcount(skb);
 
 			in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) &&
@@ -1142,7 +1143,7 @@ tcp_sacktag_write_queue(struct sock *sk,
 			    (IsFack(tp) ||
 			     !before(lost_retrans,
 				     TCP_SKB_CB(skb)->ack_seq + tp->reordering *
-				     tp->mss_cache_std))) {
+				     tp->mss_cache))) {
 				TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
 				tp->retrans_out -= tcp_skb_pcount(skb);
 
@@ -1782,7 +1783,7 @@ static void tcp_try_to_open(struct sock 
 		tp->retrans_stamp = 0;
 
 	if (flag&FLAG_ECE)
-		tcp_enter_cwr(tp);
+		tcp_enter_cwr(tp, 1);
 
 	if (tp->ca_state != TCP_CA_CWR) {
 		int state = TCP_CA_Open;
@@ -2170,7 +2171,7 @@ static void vegas_cong_avoid(struct tcp_
 		 * is the cwnd during the previous RTT.
 		 */
 		old_wnd = (tp->vegas.beg_snd_nxt - tp->vegas.beg_snd_una) /
-			tp->mss_cache_std;
+			tp->mss_cache;
 		old_snd_cwnd = tp->vegas.beg_snd_cwnd;
 
 		/* Save the extent of the current window so we can use this
@@ -2799,19 +2800,19 @@ static void westwood_dupack_update(struc
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 
-	tp->westwood.accounted += tp->mss_cache_std;
-	tp->westwood.cumul_ack = tp->mss_cache_std;
+	tp->westwood.accounted += tp->mss_cache;
+	tp->westwood.cumul_ack = tp->mss_cache;
 }
 
 static inline int westwood_may_change_cumul(struct tcp_sock *tp)
 {
-	return (tp->westwood.cumul_ack > tp->mss_cache_std);
+	return (tp->westwood.cumul_ack > tp->mss_cache);
 }
 
 static inline void westwood_partial_update(struct tcp_sock *tp)
 {
 	tp->westwood.accounted -= tp->westwood.cumul_ack;
-	tp->westwood.cumul_ack = tp->mss_cache_std;
+	tp->westwood.cumul_ack = tp->mss_cache;
 }
 
 static inline void westwood_complete_update(struct tcp_sock *tp)
@@ -2932,7 +2933,7 @@ static int tcp_ack(struct sock *sk, stru
 	if (!prior_packets)
 		goto no_queue;
 
-	prior_in_flight = tcp_packets_in_flight(tp);
+	prior_in_flight = tcp_packets_in_flight(tp) + tp->deferred;
 
 	/* See if we can take anything off of the retransmit queue. */
 	flag |= tcp_clean_rtx_queue(sk, &seq_rtt);
@@ -3948,11 +3949,11 @@ static void tcp_new_space(struct sock *s
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 
-	if (tp->packets_out < tp->snd_cwnd &&
+	if ((tp->packets_out + tp->deferred) < tp->snd_cwnd &&
 	    !(sk->sk_userlocks & SOCK_SNDBUF_LOCK) &&
 	    !tcp_memory_pressure &&
 	    atomic_read(&tcp_memory_allocated) < sysctl_tcp_mem[0]) {
- 		int sndmem = max_t(u32, tp->rx_opt.mss_clamp, tp->mss_cache_std) +
+ 		int sndmem = max_t(u32, tp->rx_opt.mss_clamp, tp->mss_cache) +
 			MAX_TCP_HEADER + 16 + sizeof(struct sk_buff),
 		    demanded = max_t(unsigned int, tp->snd_cwnd,
 						   tp->reordering + 1);
@@ -3975,16 +3976,6 @@ static inline void tcp_check_space(struc
 	}
 }
 
-static void __tcp_data_snd_check(struct sock *sk, struct sk_buff *skb)
-{
-	struct tcp_sock *tp = tcp_sk(sk);
-
-	if (after(TCP_SKB_CB(skb)->end_seq, tp->snd_una + tp->snd_wnd) ||
-	    tcp_packets_in_flight(tp) >= tp->snd_cwnd ||
-	    tcp_write_xmit(sk, tp->nonagle))
-		tcp_check_probe_timer(sk, tp);
-}
-
 static __inline__ void tcp_data_snd_check(struct sock *sk)
 {
 	struct sk_buff *skb = sk->sk_send_head;
--- 1/net/ipv4/tcp_ipv4.c.~1~	2005-05-20 22:12:09.000000000 -0700
+++ 2/net/ipv4/tcp_ipv4.c	2005-05-20 22:12:22.000000000 -0700
@@ -2060,7 +2060,8 @@ static int tcp_v4_init_sock(struct sock 
 	 */
 	tp->snd_ssthresh = 0x7fffffff;	/* Infinity */
 	tp->snd_cwnd_clamp = ~0;
-	tp->mss_cache_std = tp->mss_cache = 536;
+	tp->mss_cache = 536;
+	tp->xmit_size_cache = ~0;
 
 	tp->reordering = sysctl_tcp_reordering;
 
--- 1/net/ipv4/tcp_output.c.~1~	2005-05-20 22:12:09.000000000 -0700
+++ 2/net/ipv4/tcp_output.c	2005-05-22 21:44:07.000000000 -0700
@@ -58,6 +58,7 @@ static inline void update_send_head(stru
 	if (sk->sk_send_head == (struct sk_buff *)&sk->sk_write_queue)
 		sk->sk_send_head = NULL;
 	tp->snd_nxt = TCP_SKB_CB(skb)->end_seq;
+	tp->deferred = 0;
 	tcp_packets_out_inc(sk, tp, skb);
 }
 
@@ -141,11 +142,11 @@ static inline void tcp_event_data_sent(s
 		tp->ack.pingpong = 1;
 }
 
-static __inline__ void tcp_event_ack_sent(struct sock *sk)
+static __inline__ void tcp_event_ack_sent(struct sock *sk, unsigned int pkts)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 
-	tcp_dec_quickack_mode(tp);
+	tcp_dec_quickack_mode(tp, pkts);
 	tcp_clear_xmit_timer(sk, TCP_TIME_DACK);
 }
 
@@ -361,7 +362,7 @@ static int tcp_transmit_skb(struct sock 
 		tp->af_specific->send_check(sk, th, skb->len, skb);
 
 		if (tcb->flags & TCPCB_FLAG_ACK)
-			tcp_event_ack_sent(sk);
+			tcp_event_ack_sent(sk, tcp_skb_pcount(skb));
 
 		if (skb->len != tcp_header_size)
 			tcp_event_data_sent(tp, skb, sk);
@@ -372,7 +373,7 @@ static int tcp_transmit_skb(struct sock 
 		if (err <= 0)
 			return err;
 
-		tcp_enter_cwr(tp);
+		tcp_enter_cwr(tp, tcp_skb_pcount(skb));
 
 		/* NET_XMIT_CN is special. It does not guarantee,
 		 * that this packet is lost. It tells that device
@@ -409,42 +410,11 @@ static void tcp_queue_skb(struct sock *s
 		sk->sk_send_head = skb;
 }
 
-static inline void tcp_tso_set_push(struct sk_buff *skb)
-{
-	/* Force push to be on for any TSO frames to workaround
-	 * problems with busted implementations like Mac OS-X that
-	 * hold off socket receive wakeups until push is seen.
-	 */
-	if (tcp_skb_pcount(skb) > 1)
-		TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
-}
-
-/* Send _single_ skb sitting at the send head. This function requires
- * true push pending frames to setup probe timer etc.
- */
-void tcp_push_one(struct sock *sk, unsigned cur_mss)
-{
-	struct tcp_sock *tp = tcp_sk(sk);
-	struct sk_buff *skb = sk->sk_send_head;
-
-	if (tcp_snd_test(sk, skb, cur_mss, TCP_NAGLE_PUSH)) {
-		/* Send it out now. */
-		TCP_SKB_CB(skb)->when = tcp_time_stamp;
-		tcp_tso_set_push(skb);
-		if (!tcp_transmit_skb(sk, skb_clone(skb, sk->sk_allocation))) {
-			sk->sk_send_head = NULL;
-			tp->snd_nxt = TCP_SKB_CB(skb)->end_seq;
-			tcp_packets_out_inc(sk, tp, skb);
-			return;
-		}
-	}
-}
-
 void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 
-	if (skb->len <= tp->mss_cache_std ||
+	if (skb->len <= tp->mss_cache ||
 	    !(sk->sk_route_caps & NETIF_F_TSO)) {
 		/* Avoid the costly divide in the normal
 		 * non-TSO case.
@@ -454,10 +424,10 @@ void tcp_set_skb_tso_segs(struct sock *s
 	} else {
 		unsigned int factor;
 
-		factor = skb->len + (tp->mss_cache_std - 1);
-		factor /= tp->mss_cache_std;
+		factor = skb->len + (tp->mss_cache - 1);
+		factor /= tp->mss_cache;
 		skb_shinfo(skb)->tso_segs = factor;
-		skb_shinfo(skb)->tso_size = tp->mss_cache_std;
+		skb_shinfo(skb)->tso_size = tp->mss_cache;
 	}
 }
 
@@ -542,6 +512,7 @@ static int tcp_fragment(struct sock *sk,
 	}
 
 	/* Link BUFF into the send queue. */
+	skb_header_release(buff);
 	__skb_append(skb, buff);
 
 	return 0;
@@ -662,7 +633,7 @@ unsigned int tcp_sync_mss(struct sock *s
 
 	/* And store cached results */
 	tp->pmtu_cookie = pmtu;
-	tp->mss_cache = tp->mss_cache_std = mss_now;
+	tp->mss_cache = mss_now;
 
 	return mss_now;
 }
@@ -674,117 +645,477 @@ unsigned int tcp_sync_mss(struct sock *s
  * cannot be large. However, taking into account rare use of URG, this
  * is not a big flaw.
  */
+static inline u32 compute_xmit_cache(u32 mss, int sacks, int tso_enabled)
+{
+	u32 ret = (mss << 16) | sacks;
 
-unsigned int tcp_current_mss(struct sock *sk, int large)
+	if (tso_enabled)
+		ret |= (1 << 8);
+
+	return ret;
+}
+
+unsigned int tcp_current_mss(struct sock *sk, int large_allowed)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct dst_entry *dst = __sk_dst_get(sk);
-	unsigned int do_large, mss_now;
+	u32 mss_now;
+	u32 xmit_cache;
+	int doing_tso = 0;
+
+	mss_now = tp->mss_cache;
+
+	if (large_allowed &&
+	    (sk->sk_route_caps & NETIF_F_TSO) &&
+	    !tp->urg_mode)
+		doing_tso = 1;
 
-	mss_now = tp->mss_cache_std;
 	if (dst) {
 		u32 mtu = dst_mtu(dst);
 		if (mtu != tp->pmtu_cookie)
 			mss_now = tcp_sync_mss(sk, mtu);
 	}
 
-	do_large = (large &&
-		    (sk->sk_route_caps & NETIF_F_TSO) &&
-		    !tp->urg_mode);
-
-	if (do_large) {
-		unsigned int large_mss, factor, limit;
-
-		large_mss = 65535 - tp->af_specific->net_header_len -
-			tp->ext_header_len - tp->tcp_header_len;
-
-		if (tp->max_window && large_mss > (tp->max_window>>1))
-			large_mss = max((tp->max_window>>1),
-					68U - tp->tcp_header_len);
-
-		factor = large_mss / mss_now;
-
-		/* Always keep large mss multiple of real mss, but
-		 * do not exceed 1/tso_win_divisor of the congestion window
-		 * so we can keep the ACK clock ticking and minimize
-		 * bursting.
-		 */
-		limit = tp->snd_cwnd;
-		if (sysctl_tcp_tso_win_divisor)
-			limit /= sysctl_tcp_tso_win_divisor;
-		limit = max(1U, limit);
-		if (factor > limit)
-			factor = limit;
-
-		tp->mss_cache = mss_now * factor;
-
-		mss_now = tp->mss_cache;
-	}
+	/* If the MSS, the TSO state, or the number of SACK blocks
+	 * changes, we have to recompute tp->xmit_size_goal.
+	 */
+	xmit_cache = compute_xmit_cache(mss_now, tp->rx_opt.eff_sacks,
+					doing_tso);
 
 	if (tp->rx_opt.eff_sacks)
 		mss_now -= (TCPOLEN_SACK_BASE_ALIGNED +
 			    (tp->rx_opt.eff_sacks * TCPOLEN_SACK_PERBLOCK));
+
+	if (tp->xmit_size_cache != xmit_cache) {
+		u16 xmit_size_goal = mss_now;
+
+		if (doing_tso) {
+			xmit_size_goal = 65535 -
+				tp->af_specific->net_header_len -
+				tp->ext_header_len - tp->tcp_header_len;
+
+			if (tp->rx_opt.eff_sacks)
+				xmit_size_goal -= (TCPOLEN_SACK_BASE_ALIGNED +
+						   (tp->rx_opt.eff_sacks *
+						    TCPOLEN_SACK_PERBLOCK));
+
+			xmit_size_goal -= (xmit_size_goal % mss_now);
+		}
+		tp->xmit_size_goal = xmit_size_goal;
+		tp->xmit_size_cache = xmit_cache;
+	}
+
 	return mss_now;
 }
 
+static unsigned int tcp_window_allows(struct tcp_sock *tp, struct sk_buff *skb, unsigned int mss_now, unsigned int cwnd)
+{
+	u32 window, cwnd_len;
+
+	window = (tp->snd_una + tp->snd_wnd - TCP_SKB_CB(skb)->seq);
+	cwnd_len = mss_now * cwnd;
+	return min(window, cwnd_len);
+}
+
+/* Can at least one segment of SKB be sent right now, according
+ * to the congestion window rules?  If so, return how many segments
+ * are allowed.
+ */
+static inline unsigned int tcp_cwnd_test(struct tcp_sock *tp, struct sk_buff *skb)
+{
+	u32 in_flight, cwnd;
+
+	/* Don't be strict about the congestion window for the
+	 * final FIN frame.  -DaveM
+	 */
+	if (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)
+		return 1;
+
+	in_flight = tcp_packets_in_flight(tp);
+	cwnd = tp->snd_cwnd;
+	if (in_flight < cwnd)
+		return (cwnd - in_flight);
+
+	return 0;
+}
+
+/* This must be invoked the first time we consider transmitting
+ * SKB onto the wire.
+ */
+static inline int tcp_init_tso_segs(struct sock *sk, struct sk_buff *skb)
+{
+	int tso_segs = tcp_skb_pcount(skb);
+
+	if (!tso_segs) {
+		tcp_set_skb_tso_segs(sk, skb);
+		tso_segs = tcp_skb_pcount(skb);
+	}
+	return tso_segs;
+}
+
+/* Return 0, if packet can be sent now without violation Nagle's rules:
+ * 1. It is full sized.
+ * 2. Or it contains FIN.
+ * 3. Or TCP_NODELAY was set.
+ * 4. Or TCP_CORK is not set, and all sent packets are ACKed.
+ *    With Minshall's modification: all sent small packets are ACKed.
+ */
+
+static inline int tcp_nagle_check(const struct tcp_sock *tp,
+				  const struct sk_buff *skb, 
+				  unsigned mss_now, int nonagle)
+{
+	return (skb->len < mss_now &&
+		!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) &&
+		((nonagle&TCP_NAGLE_CORK) ||
+		 (!nonagle &&
+		  tp->packets_out &&
+		  tcp_minshall_check(tp))));
+}
+
+/* Return non-zero if the Nagle test allows this packet to be
+ * sent now.
+ */
+static inline int tcp_nagle_test(struct tcp_sock *tp, struct sk_buff *skb, unsigned int cur_mss, int nonagle)
+{
+	/* Nagle rule does not apply to frames, which
+	 * sit in the middle of queue (they have no chances
+	 * to get new data).
+	 *
+	 * This is implemented in the callers, where they modify
+	 * the 'nonagle' argument based upon the location of SKB
+	 * in the send queue.
+	 */
+	if (nonagle & TCP_NAGLE_PUSH)
+		return 1;
+
+	/* Don't use the nagle rule for urgent data (or
+	 * for the final FIN -DaveM).
+	 */
+	if (tp->urg_mode ||
+	    (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN))
+		return 1;
+
+	if (!tcp_nagle_check(tp, skb, cur_mss, nonagle))
+		return 1;
+
+	return 0;
+}
+
+/* Does at least the first segment of SKB fit into the congestion
+ * window?
+ */
+static inline int tcp_snd_wnd_test(struct tcp_sock *tp, struct sk_buff *skb, unsigned int cur_mss)
+{
+	u32 end_seq = TCP_SKB_CB(skb)->end_seq;
+
+	if (skb->len > cur_mss)
+		end_seq = TCP_SKB_CB(skb)->seq + cur_mss;
+
+	return !after(end_seq, tp->snd_una + tp->snd_wnd);
+}
+
+/* This checks if the data bearing packet SKB (usually
+ * sk->sk_send_head) should be put on the wire right now.  If so, it
+ * returns the number of packets allowed by the congestion window.
+ */
+static unsigned int tcp_snd_test(struct sock *sk, struct sk_buff *skb,
+				 unsigned cur_mss, int nonagle)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	unsigned int cwnd_quota;
+
+	if (!tcp_nagle_test(tp, skb, cur_mss, nonagle))
+		return 0;
+
+	cwnd_quota = tcp_cwnd_test(tp, skb);
+	if (cwnd_quota &&
+	    !tcp_snd_wnd_test(tp, skb, cur_mss))
+		cwnd_quota = 0;
+
+	return cwnd_quota;
+}
+
+int tcp_may_send_now(struct sock *sk, struct tcp_sock *tp)
+{
+	struct sk_buff *skb = sk->sk_send_head;
+
+	return (skb &&
+		tcp_snd_test(sk, skb, tcp_current_mss(sk, 1),
+			     tcp_skb_is_last(sk, skb) ? TCP_NAGLE_PUSH : tp->nonagle));
+}
+
+/* Trim TSO SKB to LEN bytes, put the remaining data into a new packet
+ * which is put after SKB on the list.  It is very much like
+ * tcp_fragment() except that it may make several kinds of assumptions
+ * in order to speed up the splitting operation.  In particular, we
+ * know that all the data is in scatter-gather pages, and that the
+ * packet has never been sent out before (and thus is not cloned).
+ */
+static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len)
+{
+	struct sk_buff *buff;
+	int nlen = skb->len - len;
+	u16 flags;
+
+	/* All of a TSO frame must be composed of paged data.  */
+	BUG_ON(skb->len != skb->data_len);
+
+	buff = sk_stream_alloc_pskb(sk, 0, 0, GFP_ATOMIC);
+	if (unlikely(buff == NULL))
+		return -ENOMEM;
+	sk_charge_skb(sk, buff);
+
+	buff->truesize += nlen;
+	skb->truesize -= nlen;
+
+	/* Correct the sequence numbers. */
+	TCP_SKB_CB(buff)->seq = TCP_SKB_CB(skb)->seq + len;
+	TCP_SKB_CB(buff)->end_seq = TCP_SKB_CB(skb)->end_seq;
+	TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq;
+
+	/* PSH and FIN should only be set in the second packet. */
+	flags = TCP_SKB_CB(skb)->flags;
+	TCP_SKB_CB(skb)->flags = flags & ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH);
+	TCP_SKB_CB(buff)->flags = flags;
+
+	/* This packet was never sent out yet, so no SACK bits. */
+	TCP_SKB_CB(buff)->sacked = 0;
+
+	buff->ip_summed = skb->ip_summed = CHECKSUM_HW;
+	skb_split(skb, buff, len);
+
+	/* Fix up tso_factor for both original and new SKB.  */
+	tcp_set_skb_tso_segs(sk, skb);
+	tcp_set_skb_tso_segs(sk, buff);
+
+	/* Link BUFF into the send queue. */
+	skb_header_release(buff);
+	__skb_append(skb, buff);
+
+	return 0;
+}
+
+/* Split TSO frame SKB into one MSS sized packet, then the rest.
+ * This is called during SACK processing when some SACK information
+ * hits a TSO packet.
+ */
+int tcp_tso_mince(struct sock *sk, struct tcp_sock *tp, struct sk_buff *skb)
+{
+	unsigned int mss_now = tcp_current_mss(sk, 1);
+
+	BUG_ON(tcp_skb_pcount(skb) <= 1);
+
+	/* We cannot use tso_fragment() in this case, because
+	 * the packet has been sent once already and thus may
+	 * be cloned or have other non-trivial details to deal
+	 * with.
+	 */
+	return tcp_fragment(sk, skb, mss_now);
+}
+
+/* Try to defer sending, if possible, in order
+ * to minimize the amount of TSO splitting we do.
+ * View it as a kind of TSO Nagle test.
+ *
+ * This algorithm is from John Heffner.
+ *
+ * We know that "tcp_skb_pcount(skb) > 1" and also
+ * that "tp->snd_cwnd > tcp_packets_in_flight(tp)".
+ */
+static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_buff *skb)
+{
+	u32 send_win, cong_win, limit, chunk, in_flight;
+
+	in_flight = tcp_packets_in_flight(tp);
+
+	BUG_ON(tcp_skb_pcount(skb) <= 1 ||
+	       (tp->snd_cwnd <= in_flight));
+
+	send_win = (tp->snd_una + tp->snd_wnd) - TCP_SKB_CB(skb)->seq;
+
+	/* From in_flight test above, we know that
+	 * cwnd > in_flight.
+	 */
+	cong_win = (tp->snd_cwnd - in_flight) * tp->mss_cache;
+
+	limit = min(send_win, cong_win);
+
+	/* If sk_send_head can be sent fully now, just do it.  */
+	if (skb->len <= limit)
+		return 0;
+
+	/* If at least some fraction of a window is available,
+	 * just use it.
+	 */
+	chunk = min(tp->snd_wnd, tp->snd_cwnd * tp->mss_cache);
+	chunk /= sysctl_tcp_tso_win_divisor;
+	if (limit >= chunk)
+		return 0;
+
+	/* Ok, it looks like it is advisable to defer.  */
+	if (cong_win < send_win)
+		tp->deferred = tp->snd_cwnd - in_flight;
+
+	return 1;
+}
+
 /* This routine writes packets to the network.  It advances the
  * send_head.  This happens as incoming acks open up the remote
- * window for us.
+ * window for us.  Caller makes sure sk_send_head is non-NULL.
  *
  * Returns 1, if no segments are in flight and we have queued segments, but
  * cannot send anything now because of SWS or another problem.
  */
-int tcp_write_xmit(struct sock *sk, int nonagle)
+static int tcp_write_xmit(struct sock *sk, struct tcp_sock *tp, int nonagle)
 {
-	struct tcp_sock *tp = tcp_sk(sk);
-	unsigned int mss_now;
+	unsigned int mss_now, cwnd_quota, sent_pkts, tso_segs;
+	struct sk_buff *skb;
 
 	/* If we are closed, the bytes will have to remain here.
 	 * In time closedown will finish, we empty the write queue and all
 	 * will be happy.
 	 */
-	if (sk->sk_state != TCP_CLOSE) {
-		struct sk_buff *skb;
-		int sent_pkts = 0;
+	if (unlikely(sk->sk_state == TCP_CLOSE))
+		return 0;
 
-		/* Account for SACKS, we may need to fragment due to this.
-		 * It is just like the real MSS changing on us midstream.
-		 * We also handle things correctly when the user adds some
-		 * IP options mid-stream.  Silly to do, but cover it.
-		 */
-		mss_now = tcp_current_mss(sk, 1);
+	/* Account for SACKS, we may need to fragment due to this.
+	 * It is just like the real MSS changing on us midstream.
+	 * We also handle things correctly when the user adds some
+	 * IP options mid-stream.  Silly to do, but cover it.
+	 */
+	mss_now = tcp_current_mss(sk, 1);
+
+	skb = sk->sk_send_head;
+	tso_segs = tcp_init_tso_segs(sk, skb);
+	cwnd_quota = tcp_cwnd_test(tp, skb);
+	sent_pkts = 0;
+
+	while (cwnd_quota) {
+		if (tso_segs > 1) {
+			if (tcp_tso_should_defer(sk, tp, skb))
+				break;
+		} else if (!tcp_nagle_test(tp, skb, mss_now,
+					   (tcp_skb_is_last(sk, skb) ?
+					    nonagle : TCP_NAGLE_PUSH)))
+			break;
+
+		if (!tcp_snd_wnd_test(tp, skb, mss_now))
+			break;
+
+		BUG_ON(!tso_segs);
+
+		if (tso_segs > 1) {
+			u32 limit = tcp_window_allows(tp, skb,
+						      mss_now, cwnd_quota);
 
-		while ((skb = sk->sk_send_head) &&
-		       tcp_snd_test(sk, skb, mss_now,
-			       	    tcp_skb_is_last(sk, skb) ? nonagle :
-				    			       TCP_NAGLE_PUSH)) {
-			if (skb->len > mss_now) {
-				if (tcp_fragment(sk, skb, mss_now))
+			if (skb->len > limit) {
+				if (tso_fragment(sk, skb, limit))
 					break;
 			}
-
-			TCP_SKB_CB(skb)->when = tcp_time_stamp;
-			tcp_tso_set_push(skb);
-			if (tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC)))
+		} else if (skb->len > mss_now) {
+			if (tcp_fragment(sk, skb, mss_now))
 				break;
+		}
 
-			/* Advance the send_head.  This one is sent out.
-			 * This call will increment packets_out.
-			 */
-			update_send_head(sk, tp, skb);
+		TCP_SKB_CB(skb)->when = tcp_time_stamp;
+		if (tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC)))
+			break;
 
-			tcp_minshall_update(tp, mss_now, skb);
-			sent_pkts = 1;
-		}
+		/* Advance the send_head.  This one is sent out.
+		 * This call will increment packets_out.
+		 */
+		update_send_head(sk, tp, skb);
 
-		if (sent_pkts) {
-			tcp_cwnd_validate(sk, tp);
-			return 0;
+		tcp_minshall_update(tp, mss_now, skb);
+		sent_pkts++;
+
+		cwnd_quota -= tcp_skb_pcount(skb);
+		skb = sk->sk_send_head;
+		if (!skb)
+			break;
+		tso_segs = tcp_init_tso_segs(sk, skb);
+	}
+
+	if (sent_pkts) {
+		tcp_cwnd_validate(sk, tp);
+		return 0;
+	}
+
+	return !tp->packets_out && sk->sk_send_head;
+}
+
+/* Push out any pending frames which were held back due to
+ * TCP_CORK or attempt at coalescing tiny packets.
+ * The socket must be locked by the caller.
+ */
+void __tcp_push_pending_frames(struct sock *sk,
+			       struct tcp_sock *tp,
+			       unsigned int cur_mss,
+			       int nonagle)
+{
+	if (sk->sk_send_head) {
+		if (tcp_write_xmit(sk, tp, nonagle))
+			tcp_check_probe_timer(sk, tp);
+	}
+}
+
+/* As ACKs arrive and the send and congestion windows potentially
+ * open up, we call this to try and make write queue transmit
+ * progress.
+ *
+ * The caller has the socket locked, and has verified that
+ * sk->sk_send_head is not NULL.
+ */
+void __tcp_data_snd_check(struct sock *sk, struct sk_buff *skb)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+
+	if (tcp_write_xmit(sk, tp, tp->nonagle))
+		tcp_check_probe_timer(sk, tp);
+}
+
+/* Send _single_ skb sitting at the send head. This function requires
+ * true push pending frames to setup probe timer etc.  Caller makes
+ * sure that sk->sk_send_head is non-NULL.
+ */
+void tcp_push_one(struct sock *sk, unsigned int cur_mss)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct sk_buff *skb = sk->sk_send_head;
+	unsigned int tso_segs, cwnd_quota;
+
+	tso_segs = tcp_init_tso_segs(sk, skb);
+	cwnd_quota = tcp_snd_test(sk, skb, cur_mss, TCP_NAGLE_PUSH);
+
+	if (cwnd_quota && tso_segs > 1) {
+		if (tcp_tso_should_defer(sk, tp, skb))
+			return;
+	}
+
+	if (cwnd_quota) {
+		BUG_ON(!tso_segs);
+
+		if (tso_segs > 1) {
+			u32 limit = tcp_window_allows(tp, skb,
+						      cur_mss, cwnd_quota);
+
+			if (skb->len > limit) {
+				if (tso_fragment(sk, skb, limit))
+					return;
+			}
+		} else if (skb->len > cur_mss) {
+			if (tcp_fragment(sk, skb, cur_mss))
+				return;
 		}
 
-		return !tp->packets_out && sk->sk_send_head;
+		/* Send it out now. */
+		TCP_SKB_CB(skb)->when = tcp_time_stamp;
+		if (!tcp_transmit_skb(sk, skb_clone(skb, sk->sk_allocation))) {
+			update_send_head(sk, tp, skb);
+			return;
+		}
 	}
-	return 0;
 }
 
 /* This function returns the amount that we can raise the
@@ -1041,12 +1372,6 @@ int tcp_retransmit_skb(struct sock *sk, 
 		if (before(TCP_SKB_CB(skb)->end_seq, tp->snd_una))
 			BUG();
 
-		if (sk->sk_route_caps & NETIF_F_TSO) {
-			sk->sk_route_caps &= ~NETIF_F_TSO;
-			sock_set_flag(sk, SOCK_NO_LARGESEND);
-			tp->mss_cache = tp->mss_cache_std;
-		}
-
 		if (tcp_trim_head(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq))
 			return -ENOMEM;
 	}
@@ -1106,7 +1431,6 @@ int tcp_retransmit_skb(struct sock *sk, 
 	 * is still in somebody's hands, else make a clone.
 	 */
 	TCP_SKB_CB(skb)->when = tcp_time_stamp;
-	tcp_tso_set_push(skb);
 
 	err = tcp_transmit_skb(sk, (skb_cloned(skb) ?
 				    pskb_copy(skb, GFP_ATOMIC):
@@ -1671,19 +1995,11 @@ int tcp_write_wakeup(struct sock *sk)
 				TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
 				if (tcp_fragment(sk, skb, seg_size))
 					return -1;
-				/* SWS override triggered forced fragmentation.
-				 * Disable TSO, the connection is too sick. */
-				if (sk->sk_route_caps & NETIF_F_TSO) {
-					sock_set_flag(sk, SOCK_NO_LARGESEND);
-					sk->sk_route_caps &= ~NETIF_F_TSO;
-					tp->mss_cache = tp->mss_cache_std;
-				}
 			} else if (!tcp_skb_pcount(skb))
 				tcp_set_skb_tso_segs(sk, skb);
 
 			TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
 			TCP_SKB_CB(skb)->when = tcp_time_stamp;
-			tcp_tso_set_push(skb);
 			err = tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC));
 			if (!err) {
 				update_send_head(sk, tp, skb);
--- 1/net/ipv6/tcp_ipv6.c.~1~	2005-05-20 22:12:09.000000000 -0700
+++ 2/net/ipv6/tcp_ipv6.c	2005-05-20 22:12:22.000000000 -0700
@@ -2021,7 +2021,8 @@ static int tcp_v6_init_sock(struct sock 
 	 */
 	tp->snd_ssthresh = 0x7fffffff;
 	tp->snd_cwnd_clamp = ~0;
-	tp->mss_cache_std = tp->mss_cache = 536;
+	tp->mss_cache = 536;
+	tp->xmit_size_cache = ~0;
 
 	tp->reordering = sysctl_tcp_reordering;
 

[-- Attachment #3: tcp_ack26.diff --]
[-- Type: Text/Plain, Size: 466 bytes --]

diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4355,16 +4355,7 @@ int tcp_rcv_established(struct sock *sk,
 					goto no_ack;
 			}
 
-			if (eaten) {
-				if (tcp_in_quickack_mode(tp)) {
-					tcp_send_ack(sk);
-				} else {
-					tcp_send_delayed_ack(sk);
-				}
-			} else {
-				__tcp_ack_snd_check(sk, 0);
-			}
-
+			__tcp_ack_snd_check(sk, 0);
 no_ack:
 			if (eaten)
 				__kfree_skb(skb);

[-- Attachment #4: tcp_ack24.diff --]
[-- Type: Text/Plain, Size: 1111 bytes --]

[TCP]: Fix stretch ACK performance killer when doing ucopy.

When we are doing ucopy, we try to defer the ACK generation to
cleanup_rbuf().  This works most of the time very well, but if the
ucopy prequeue is large, this ACKing behavior kills performance.

With TSO, it is possible to fill the prequeue so large that by the
time the ACK is sent and gets back to the sender, most of the window
has emptied of data and performance suffers significantly.

This behavior does help in some cases, so we should think about
re-enabling this trick in the future, using some kind of limit in
order to avoid the bug case.

Signed-off-by: David S. Miller <davem@davemloft.net>

--- 1/net/ipv4/tcp_input.c.~1~	2005-05-23 12:03:26.000000000 -0700
+++ 2/net/ipv4/tcp_input.c	2005-05-23 12:03:28.000000000 -0700
@@ -4243,16 +4243,7 @@
 					goto no_ack;
 			}
 
-			if (eaten) {
-				if (tcp_in_quickack_mode(tp)) {
-					tcp_send_ack(sk);
-				} else {
-					tcp_send_delayed_ack(sk);
-				}
-			} else {
-				__tcp_ack_snd_check(sk, 0);
-			}
-
+			__tcp_ack_snd_check(sk, 0);
 no_ack:
 			if (eaten)
 				__kfree_skb(skb);

^ permalink raw reply

* Re: [PATCH] bonding using arp_ip_target may stay down with active path
From: David S. Miller @ 2005-05-23 19:51 UTC (permalink / raw)
  To: fubar; +Cc: eparis, netdev, jgarzik, bonding-devel
In-Reply-To: <200505162034.j4GKYbch022992@death.nxdomain.ibm.com>


Patch doesn't apply, tabs turned into spaces by your
email client.

^ permalink raw reply

* Re: [PATCH] include/linux/if_tr.h clean-up
From: David S. Miller @ 2005-05-23 19:53 UTC (permalink / raw)
  To: jdmason; +Cc: netdev
In-Reply-To: <20050520221019.GA26211@us.ibm.com>

From: Jon Mason <jdmason@us.ibm.com>
Date: Fri, 20 May 2005 17:10:19 -0500

> I removed the ethernet definitions (which were commented out) and
> cleaned up the tabs.
> 
> Signed-off-by: Jon Mason <jdmason@us.ibm.com>

Looks fine, applied.

Thanks Jon.

^ permalink raw reply

* Re: [PATCH] netdevice.h: be'ify packet_type
From: David S. Miller @ 2005-05-23 20:09 UTC (permalink / raw)
  To: adobriyan; +Cc: netdev
In-Reply-To: <200505211940.59240.adobriyan@gmail.com>

From: Alexey Dobriyan <adobriyan@gmail.com>
Date: Sat, 21 May 2005 19:40:59 +0400

> Everybody does
> 
> 	struct packet_type foo_packet_type = {
> 		.type = __constant_htons(ETH_P_FOO);
> 	};
> 
> 5 introduced warnings will be properly fixed later.
> 
> Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>

Looks great, patch applied.

Thanks.

^ permalink raw reply

* Re: [BUG 2.6.12-rc4] IPv6 xfrm tunnel oops with large packets
From: David S. Miller @ 2005-05-23 20:11 UTC (permalink / raw)
  To: yoshfuji; +Cc: herbert, christophe, linux-net, netdev
In-Reply-To: <20050522.051817.122678688.yoshfuji@linux-ipv6.org>

From: YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org>
Date: Sun, 22 May 2005 05:18:17 +0900 (JST)

> In article <20050521194932.GA10959@gondor.apana.org.au> (at Sun, 22 May 2005 05:49:32 +1000), Herbert Xu <herbert@gondor.apana.org.au> says:
> 
> > On Sat, May 21, 2005 at 07:10:11PM +0000, Christophe Saout wrote:
> > > 
> > > The oops occurs in line 391 in net/ipv6/icmp.c:
> > > 
> > > >        idev = in6_dev_get(skb->dev);
> > 
> > Here is a minimal fix.
> > 
> > Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
> 
> 
> Acked-by: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>

Applied, thanks everyone.

^ permalink raw reply

* Re: Why /sys/class/net/*/features is read-only?
From: Catalin(ux aka Dino) BOIE @ 2005-05-23 20:49 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20050523092827.7883af33@dxpl.pdx.osdl.net>

On Mon, 23 May 2005, Stephen Hemminger wrote:

> On Mon, 23 May 2005 10:46:50 +0300 (EEST)
> "Catalin(ux aka Dino) BOIE" <util@deuroconsult.ro> wrote:
>
>> Hello!
>>
>> Why features file is read-only. If an admin want to force some attributes,
>> we can let them, right?
>>
>
> Leave it read-only because the hardware may not want to allow them on that flavor and so it would
> have to be device specific.

You are clear right for hardware devices, but for software ones (bridge 
for example) it makes sense. Anyway, only admin can change them.

If you have a bridge with 5 net cards and 4 supports SG, some people 
may want to force SG on the bridge.

---
Catalin(ux aka Dino) BOIE
catab at deuroconsult.ro
http://kernel.umbrella.ro/

^ permalink raw reply

* [PATCH linux-2.6.12-rc4-mm1] via-rhine: init clean-up
From: Jon Mason @ 2005-05-23 20:50 UTC (permalink / raw)
  To: rl; +Cc: netdev

Removed unnecessary IF checks and variable assignments, as pci_revs are
either < VTunknown0 or >= VT6102.  

dev->features is never populated.  So, there could be garbage in there
(then OR'ed with NETIF_F_SG | NETIF_F_HW_CSUM).  Also,
ethtool_op_get_tx_csum checks for NETIF_F_IP_CSUM not NETIF_F_HW_CSUM.
I am sending out a patch to fix that (in ethtool.c) shortly.

Signed-off-by: Jon Mason <jdmason@us.ibm.com>

--- drivers/net/via-rhine.c.orig	2005-05-21 10:52:01.000000000 -0500
+++ drivers/net/via-rhine.c	2005-05-21 15:07:29.000000000 -0500
@@ -710,21 +710,18 @@ static int __devinit rhine_init_one(stru
 
 	pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
 
-	io_size = 256;
 	phy_id = 0;
-	quirks = 0;
-	name = "Rhine";
 	if (pci_rev < VTunknown0) {
+		name = "Rhine";
 		quirks = rqRhineI;
 		io_size = 128;
-	}
-	else if (pci_rev >= VT6102) {
+	} else { 
+		io_size = 256;
 		quirks = rqWOL | rqForceReset;
 		if (pci_rev < VT6105) {
 			name = "Rhine II";
 			quirks |= rqStatusWBRace;	/* Rhine-II exclusive */
-		}
-		else {
+		} else {
 			phy_id = 1;	/* Integrated PHY, phy_id fixed to 1 */
 			if (pci_rev >= VT6105_B0)
 				quirks |= rq6patterns;
@@ -847,7 +844,7 @@ static int __devinit rhine_init_one(stru
 	dev->poll_controller = rhine_poll;
 #endif
 	if (rp->quirks & rqRhineI)
-		dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
+		dev->features = NETIF_F_SG | NETIF_F_HW_CSUM;
 
 	/* dev->name not defined before register_netdev()! */
 	rc = register_netdev(dev);

^ permalink raw reply

* Re: Why /sys/class/net/*/features is read-only?
From: David S. Miller @ 2005-05-23 20:53 UTC (permalink / raw)
  To: util; +Cc: shemminger, netdev
In-Reply-To: <Pine.LNX.4.62.0505232346310.17855@webhosting.rdsbv.ro>

From: "Catalin(ux aka Dino) BOIE" <util@deuroconsult.ro>
Date: Mon, 23 May 2005 23:49:57 +0300 (EEST)

> If you have a bridge with 5 net cards and 4 supports SG, some people 
> may want to force SG on the bridge.

Let them use ethtool :-)

^ permalink raw reply

* Re: Why /sys/class/net/*/features is read-only?
From: Stephen Hemminger @ 2005-05-23 20:55 UTC (permalink / raw)
  To: Catalin(ux aka Dino) BOIE; +Cc: netdev
In-Reply-To: <Pine.LNX.4.62.0505232346310.17855@webhosting.rdsbv.ro>

On Mon, 23 May 2005 23:49:57 +0300 (EEST)
"Catalin(ux aka Dino) BOIE" <util@deuroconsult.ro> wrote:

> On Mon, 23 May 2005, Stephen Hemminger wrote:
> 
> > On Mon, 23 May 2005 10:46:50 +0300 (EEST)
> > "Catalin(ux aka Dino) BOIE" <util@deuroconsult.ro> wrote:
> >
> >> Hello!
> >>
> >> Why features file is read-only. If an admin want to force some attributes,
> >> we can let them, right?
> >>
> >
> > Leave it read-only because the hardware may not want to allow them on that flavor and so it would
> > have to be device specific.
> 
> You are clear right for hardware devices, but for software ones (bridge 
> for example) it makes sense. Anyway, only admin can change them.
> 
> If you have a bridge with 5 net cards and 4 supports SG, some people 
> may want to force SG on the bridge.

Then implement ethtool on the bridge device, it wouldn't be hard to do that.

^ permalink raw reply

* Re: [PATCH] netem: fix logic bug in reorder conditional
From: Julio Kriger @ 2005-05-23 20:55 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: David S. Miller, netdev, netem
In-Reply-To: <20050523104342.78b1032d@dxpl.pdx.osdl.net>

Hi!

1) Supouse I don't want reordering, so in 'tc' I don't add reorder
option. Will this code work? The previous (on this subject) patch has
a the following:

+       /* for compatiablity with earlier versions.
+        * if gap is set, need to assume 100% probablity
+        */
+       q->reorder = ~0;
+

Should it be set to 100% or 101%? 
This "q->reorder = ~0;" mean 100%?

2) If I set latency = 50ms and a jitter = 300ms, tabledist can give me
a negative number. This value is addes to cb->time_to_send, so it
could change it to a negative value. Should we only accept positives
number before add it to cb->time_to_send? or will
q->qdisc->enqueue(skb, q->qdisc) put the package on the queue in a
special way so it will be handled "before" other packages alrealy on
the queue but with gretaer time_to_send?

Regards,
Julio

On 5/23/05, Stephen Hemminger <shemminger@osdl.org> wrote:
> Thanks, Julio you spotted the problem with the logic.  This should fix it:
> 
> Index: netem-2.6.12-rc4/net/sched/sch_netem.c
> ===================================================================
> --- netem-2.6.12-rc4.orig/net/sched/sch_netem.c
> +++ netem-2.6.12-rc4/net/sched/sch_netem.c
> @@ -181,13 +181,9 @@ static int netem_enqueue(struct sk_buff
>                 q->duplicate = dupsave;
>         }
> 
> -       /*
> -        * Do re-ordering by putting one out of N packets at the front
> -        * of the queue.
> -        * gap == 0 is special case for no-reordering.
> -        */
> -       if (q->gap == 0 && q->counter < q->gap &&
> -           q->reorder < get_crandom(&q->reorder_cor)) {
> +       if (q->gap == 0                 /* not doing reordering */
> +           || q->counter < q->gap      /* inside last reordering gap */
> +           || q->reorder < get_crandom(&q->reorder_cor)) {
>                 psched_time_t now;
>                 PSCHED_GET_TIME(now);
>                 PSCHED_TADD2(now, tabledist(q->latency, q->jitter,
> @@ -196,6 +192,10 @@ static int netem_enqueue(struct sk_buff
>                 ++q->counter;
>                 ret = q->qdisc->enqueue(skb, q->qdisc);
>         } else {
> +               /*
> +                * Do re-ordering by putting one out of N packets at the front
> +                * of the queue.
> +                */
>                 PSCHED_GET_TIME(cb->time_to_send);
>                 q->counter = 0;
>                 ret = q->qdisc->ops->requeue(skb, q->qdisc);
> 


-- 
----------------------------
Julio Kriger
mailto:juliokriger@gmail.com

^ permalink raw reply

* Re: [PATCH] netem: fix logic bug in reorder conditional
From: Stephen Hemminger @ 2005-05-23 21:00 UTC (permalink / raw)
  To: Julio Kriger; +Cc: David S. Miller, netdev, netem
In-Reply-To: <682bc30a050523135534b38b8b@mail.gmail.com>

On Mon, 23 May 2005 17:55:35 -0300
Julio Kriger <juliokriger@gmail.com> wrote:

> Hi!
> 
> 1) Supouse I don't want reordering, so in 'tc' I don't add reorder
> option. Will this code work? The previous (on this subject) patch has
> a the following:
> 
> +       /* for compatiablity with earlier versions.
> +        * if gap is set, need to assume 100% probablity
> +        */
> +       q->reorder = ~0;
> +

If you don't want reordering, then gap = 0. so reorder is ignored.

> 
> Should it be set to 100% or 101%? 
> This "q->reorder = ~0;" mean 100%?
yes probability percentages are converted to 32-bit unsigned long scaled
value.  so 100% = 0xffffffff and 0% = 0

> 2) If I set latency = 50ms and a jitter = 300ms, tabledist can give me
> a negative number. This value is addes to cb->time_to_send, so it
> could change it to a negative value. Should we only accept positives
> number before add it to cb->time_to_send? or will
> q->qdisc->enqueue(skb, q->qdisc) put the package on the queue in a
> special way so it will be handled "before" other packages alrealy on
> the queue but with gretaer time_to_send?

probably should bound the value to 0 before the addition, to avoid large
wraparound problems, but since enqueue checks for for time it will work
as long as delta less than 2^32/2.

^ permalink raw reply

* [PATCH linux-2.6.12-rc4-mm1] ethtool: Add NETIF_F_HW_CSUM support
From: Jon Mason @ 2005-05-23 21:07 UTC (permalink / raw)
  To: netdev

Added support to ethtool for NETIF_F_HW_CSUM.

Signed-off-by: Jon Mason <jdmason@us.ibm.com>

--- include/linux/ethtool.h.orig	2005-05-16 08:49:43.000000000 -0500
+++ include/linux/ethtool.h	2005-05-21 15:11:05.000000000 -0500
@@ -256,6 +256,7 @@ struct net_device;
 u32 ethtool_op_get_link(struct net_device *dev);
 u32 ethtool_op_get_tx_csum(struct net_device *dev);
 int ethtool_op_set_tx_csum(struct net_device *dev, u32 data);
+int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data);
 u32 ethtool_op_get_sg(struct net_device *dev);
 int ethtool_op_set_sg(struct net_device *dev, u32 data);
 u32 ethtool_op_get_tso(struct net_device *dev);
--- net/core/ethtool.c.orig	2005-05-21 14:16:33.000000000 -0500
+++ net/core/ethtool.c	2005-05-21 18:07:16.000000000 -0500
@@ -29,7 +29,7 @@ u32 ethtool_op_get_link(struct net_devic
 
 u32 ethtool_op_get_tx_csum(struct net_device *dev)
 {
-	return (dev->features & NETIF_F_IP_CSUM) != 0;
+	return (dev->features & (NETIF_F_IP_CSUM | NETIF_F_HW_CSUM)) != 0;
 }
 
 int ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
@@ -42,6 +42,15 @@ int ethtool_op_set_tx_csum(struct net_de
 	return 0;
 }
 
+int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data)
+{
+	if (data)
+		dev->features |= NETIF_F_HW_CSUM;
+	else
+		dev->features &= ~NETIF_F_HW_CSUM;
+
+	return 0;
+}
 u32 ethtool_op_get_sg(struct net_device *dev)
 {
 	return (dev->features & NETIF_F_SG) != 0;
@@ -817,3 +826,4 @@ EXPORT_SYMBOL(ethtool_op_get_tx_csum);
 EXPORT_SYMBOL(ethtool_op_set_sg);
 EXPORT_SYMBOL(ethtool_op_set_tso);
 EXPORT_SYMBOL(ethtool_op_set_tx_csum);
+EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum);

^ permalink raw reply

* Re: [PATCH linux-2.6.12-rc4-mm1] ethtool: Add NETIF_F_HW_CSUM support
From: David S. Miller @ 2005-05-23 21:20 UTC (permalink / raw)
  To: jdmason; +Cc: netdev
In-Reply-To: <20050523210757.GB5910@us.ibm.com>

From: Jon Mason <jdmason@us.ibm.com>
Subject: [PATCH linux-2.6.12-rc4-mm1] ethtool: Add NETIF_F_HW_CSUM support
Date: Mon, 23 May 2005 16:07:57 -0500

> Added support to ethtool for NETIF_F_HW_CSUM.
> 
> Signed-off-by: Jon Mason <jdmason@us.ibm.com>

You cannot blindly set these flags, you need to provide
a method for the driver to override the implementation of
this method so it can return and error if it cannot provide
support for this feature.

^ permalink raw reply

* Re: [PATCH] bonding using arp_ip_target may stay down with active path
From: Jay Vosburgh @ 2005-05-23 21:21 UTC (permalink / raw)
  To: David S. Miller; +Cc: eparis, netdev, jgarzik, bonding-devel
In-Reply-To: <20050523.125107.45741257.davem@davemloft.net>


David S. Miller <davem@davemloft.net> wrote:
>Patch doesn't apply, tabs turned into spaces by your
>email client.

	As penance for test applying trivial patches by hand, here's a
proper version.

	-J

---
	-Jay Vosburgh, IBM Linux Technology Center, fubar@us.ibm.com


Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>

diff -urN linux-2.6.11/drivers/net/bonding/bond_main.c linux-2.6.11-fix/drivers/net/bonding/bond_main.c
--- linux-2.6.11/drivers/net/bonding/bond_main.c	2005-05-23 14:07:37.000000000 -0700
+++ linux-2.6.11-fix/drivers/net/bonding/bond_main.c	2005-05-23 14:08:13.000000000 -0700
@@ -3046,7 +3046,7 @@
 			bond_set_slave_inactive_flags(bond->current_arp_slave);
 
 			/* search for next candidate */
-			bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave) {
+			bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave->next) {
 				if (IS_UP(slave->dev)) {
 					slave->link = BOND_LINK_BACK;
 					bond_set_slave_active_flags(slave);

^ permalink raw reply

* Re: [PATCH] Implement NETDEV_FEAT_CHANGE
From: Catalin(ux aka Dino) BOIE @ 2005-05-23 21:32 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, davem
In-Reply-To: <20050523093329.40617690@dxpl.pdx.osdl.net>

On Mon, 23 May 2005, Stephen Hemminger wrote:

>
>> --- notify1/net/core/ethtool.c	2005-03-02 09:38:37.000000000 +0200
>> +++ linux/net/core/ethtool.c	2005-05-23 11:30:47.000000000 +0300
> ...
>> @@ -712,7 +715,6 @@ int dev_ethtool(struct ifreq *ifr)
>>  		break;
>>  	case ETHTOOL_GDRVINFO:
>>  		rc = ethtool_get_drvinfo(dev, useraddr);
>> -
>>  		break;
>
> White space creep

Do you want to not touch that space?

>>  	case ETHTOOL_GREGS:
>>  		rc = ethtool_get_regs(dev, useraddr);
>> @@ -801,6 +803,10 @@ int dev_ethtool(struct ifreq *ifr)
>>
>>  	if(dev->ethtool_ops->complete)
>>  		dev->ethtool_ops->complete(dev);
>> +
>> +	if (old_features != dev->features)
>> +		netdev_features_change(dev);
>> +
>>  	return rc;
>>
>>   ioctl:
>
> Did you check for any  drivers that don't use ethtool_ops?

I checked now and I didn't find any possibility to change features.
So I think we are ok.

---
Catalin(ux aka Dino) BOIE
catab at deuroconsult.ro
http://kernel.umbrella.ro/

^ permalink raw reply

* Re: [PATCH linux-2.6.12-rc4-mm1] ethtool: Add NETIF_F_HW_CSUM support
From: Jon Mason @ 2005-05-23 21:32 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev
In-Reply-To: <20050523.142009.74748115.davem@davemloft.net>

On Monday 23 May 2005 04:20 pm, David S. Miller wrote:
> From: Jon Mason <jdmason@us.ibm.com>
> Subject: [PATCH linux-2.6.12-rc4-mm1] ethtool: Add NETIF_F_HW_CSUM support
> Date: Mon, 23 May 2005 16:07:57 -0500
>
> > Added support to ethtool for NETIF_F_HW_CSUM.
> >
> > Signed-off-by: Jon Mason <jdmason@us.ibm.com>
>
> You cannot blindly set these flags, you need to provide
> a method for the driver to override the implementation of
> this method so it can return and error if it cannot provide
> support for this feature.

I am only adding a generic function which gives the ability to use 
NETIF_F_HW_CSUM for ethtool tx offload (instead of only using 
NETIF_F_IP_CSUM).

If ethtool_set_tx_csum does not point to ethtool_op_set_tx_csum or 
ethtool_op_set_tx_hw_csum (or a local driver function) then it will return an 
error.  Isn't this sufficient (as it is what currently happening), or am I 
not sufficently understanding the problem?

Thanks,
Jon

^ permalink raw reply

* Re: Why /sys/class/net/*/features is read-only?
From: Catalin(ux aka Dino) BOIE @ 2005-05-23 21:33 UTC (permalink / raw)
  To: David S. Miller; +Cc: shemminger, netdev
In-Reply-To: <20050523.135348.55831423.davem@davemloft.net>

On Mon, 23 May 2005, David S. Miller wrote:

> From: "Catalin(ux aka Dino) BOIE" <util@deuroconsult.ro>
> Date: Mon, 23 May 2005 23:49:57 +0300 (EEST)
>
>> If you have a bridge with 5 net cards and 4 supports SG, some people
>> may want to force SG on the bridge.
>
> Let them use ethtool :-)

They can't on a bridge device, right?

---
Catalin(ux aka Dino) BOIE
catab at deuroconsult.ro
http://kernel.umbrella.ro/

^ permalink raw reply

* Re: [PATCH] Super TSO v3
From: Herbert Xu @ 2005-05-23 21:34 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev
In-Reply-To: <20050523.121943.78708600.davem@davemloft.net>

David S. Miller <davem@davemloft.net> wrote:
> 
> I discoevered a performance anomaly with Linux receivers,
> cause by enormous stretch ACK generation, which you'll need
> to fix if you want to test this patch against Linux receivers.

Are there non-Linux systems that have the same receive issue?
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox