* Re: [RFC/PATCH] "strict" ipv4 reassembly
From: Andi Kleen @ 2005-05-18 1:05 UTC (permalink / raw)
To: David S. Miller; +Cc: niv, akepner, dlstevens, rick.jones2, netdev
In-Reply-To: <20050517.175126.74751342.davem@davemloft.net>
"David S. Miller" <davem@davemloft.net> writes:
> From: Herbert Xu <herbert@gondor.apana.org.au>
> Subject: Re: [RFC/PATCH] "strict" ipv4 reassembly
> Date: Wed, 18 May 2005 10:10:54 +1000
>
>> On Tue, May 17, 2005 at 05:06:55PM -0700, Nivedita Singhvi wrote:
>> >
>> > Mainline linux certainly has this (per-inetpeer ip_id) - but
>> > at least one distro did not (use inetpeer) :). Not sure
>> > what the current situation is.
>>
>> What was the reason for this? Perhaps we can solve their problems
>> with inetpeer in a better way than disabling it?
>
> Andi Kleen thought inetpeer was a pig, so he removed it from SUSE's
> kernel and replaced it with a per-cpu salted IP ID generator. The
> initial verion he wrote had serious bugs that severely decreased the
> effective ID space, and thus made the NFS corruption problem happen
> more frequently.
That's not true, there were no bugs it in. Or at least none
I know about.
However any randomized IPID scheme decreases the effective IP-ID
space slightly. The only algorithm that uses a bit space perfectly
is a counter :) However I admit the constant to regulate the grainness
was a bit too aggressive at the beginning, which indeed triggered
the NFS corruption problem more frequently. However since the 16bit
space is more or less useless (as Artur demonstrated it cannot
even handle a single Gigabit link) it did not make that much difference anyways.
The eventual workaround for the NFS IP-ID problem that went into
the vendor kernel also did work in a different way on top
of the algorithm.
As for the background (not for you Dave, for other readers ;-) why I
consider inetpeer useless please read the archives. As a hint just
look what kind of functionality it implements and how much of it is
actually enabled by default and think of its relationship to masquerading
(which BTW breaks most of the fancy algorithms proposed so far)
-Andi
^ permalink raw reply
* Re: [RFC/PATCH] "strict" ipv4 reassembly
From: Arthur Kepner @ 2005-05-18 1:06 UTC (permalink / raw)
To: Rick Jones, Herbert Xu; +Cc: David S. Miller, Thomas Graf, netdev
In-Reply-To: <20050518004733.GG13748@postel.suug.ch>
It sounds as if Herbert and Rick have much the same idea. And
it sounds like a good idea, definitely worth considering...
On Wed, 18 May 2005, Thomas Graf wrote:
> * Herbert Xu <E1DYAHF-0006qW-00@gondolin.me.apana.org.au> 2005-05-18 08:11
> > Instead of measuring the distance using time, let's measure it
> > in terms of packet counts. So every time we receive a fragmented
> > packet, we find all waiting fragments with the same src/dst pair.
> > If the id is identical we perform reassembly, if it isn't we increase
> > a counter in that fragment. If the counter exceeds a threshold,
> > we drop the fragment.
>
> I like this, although the problem is derived to the definition
> of the threshold. Any ideas on how to define this? A
> combination of your idea together with the idea I stated in
> another post which would additional expire fragments earlier
> depending on the actual packet (or fragment) rate might give
> better results.
>
------------------------------ [snip] ------------------------------
> On Tue, 17 May 2005, Rick Jones wrote:
> .....
> Actually, I was ass-u-me-ing they would be monotonic, but thinking about
> it more, that doesn't really matter. If N datagrams from that
> source/dest/prot tuple have been reassembled since the first/current
> frag of this datagam has arrived, chances are still good that the rest
> of the fragments of this datagram are toast and any subsequent
> fragments with a matching src/dst/prot/id would likely create a
> frankengram.
>
> in broad handwaving terms, those N other datagrams (non-fragmented or
> fragmented and successfully reassembled or not I suspect) are a measure
> of just how far "out of order" the rest of the fragments of this
> datagram happen to be. for some degree of "out of orderness" we can
> ass-u-me the datagram is toast.
>
> chosing a strawman, if we've received 24000 datagrams from that
> source/dest/prot (perhaps even just that source) since we've started
> reassembling this datagram from that source/dest/prot, chances seem
> pretty good indeed that this datagram is toast. a value of N even
> smaller than 24000 might suffice.
>
> the devil seems to be in the accounting.
------------------------------ [snip] ------------------------------
^ permalink raw reply
* Re: [RFC/PATCH] "strict" ipv4 reassembly
From: John Heffner @ 2005-05-18 1:09 UTC (permalink / raw)
To: Herbert Xu; +Cc: netdev, Arthur Kepner, dlstevens, rick.jones2
In-Reply-To: <20050517232556.GA26846@gondor.apana.org.au>
On May 17, 2005, at 7:25 PM, Herbert Xu wrote:
>
> Perhaps you misunderstood what I was saying. I meant are there any
> extant systems that would transmit 1 set of fragments to host A with
> id x, then 65535 packets host B, and then wrap around and send a new
> set of fragments to host A with idx.
>
> Linux will never do this thanks to inetpeer.c.
Of course (as usual) NATs break everything. ;-)
There are also the ugly case where fragments could be delayed in the
network for a period of time, for example during a path change, and
show up at exactly the wrong time.
-John
^ permalink raw reply
* Re: [RFC/PATCH] "strict" ipv4 reassembly
From: Herbert Xu @ 2005-05-18 1:13 UTC (permalink / raw)
To: David S. Miller; +Cc: niv, akepner, dlstevens, rick.jones2, netdev
In-Reply-To: <20050517.175126.74751342.davem@davemloft.net>
On Tue, May 17, 2005 at 05:51:26PM -0700, David S. Miller wrote:
>
> Andi Kleen thought inetpeer was a pig, so he removed it from SUSE's
> kernel and replaced it with a per-cpu salted IP ID generator. The
> initial verion he wrote had serious bugs that severely decreased the
> effective ID space, and thus made the NFS corruption problem happen
> more frequently.
Is he turning off PMTU by default as well? :) I don't see how it
can be a pig otherwise.
--
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
* Re: [RFC/PATCH] "strict" ipv4 reassembly
From: Herbert Xu @ 2005-05-18 1:16 UTC (permalink / raw)
To: Thomas Graf; +Cc: David S. Miller, akepner, netdev
In-Reply-To: <20050518004733.GG13748@postel.suug.ch>
On Wed, May 18, 2005 at 02:47:33AM +0200, Thomas Graf wrote:
>
> I like this, although the problem is derived to the definition
> of the threshold. Any ideas on how to define this? A
The threshold doesn't need to be very large at all since it is
essentially the maximum reordering distance that we allow.
However, for an initial estimate we can be conservative and
use something like 30000. If we're too conservative the SGI
guys will tell us :)
Cheers,
--
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
* Re: [RFC/PATCH] "strict" ipv4 reassembly
From: Thomas Graf @ 2005-05-18 1:37 UTC (permalink / raw)
To: Herbert Xu; +Cc: David S. Miller, akepner, netdev
In-Reply-To: <20050518011632.GA27813@gondor.apana.org.au>
* Herbert Xu <20050518011632.GA27813@gondor.apana.org.au> 2005-05-18 11:16
> On Wed, May 18, 2005 at 02:47:33AM +0200, Thomas Graf wrote:
> >
> > I like this, although the problem is derived to the definition
> > of the threshold. Any ideas on how to define this? A
>
> The threshold doesn't need to be very large at all since it is
> essentially the maximum reordering distance that we allow.
>
> However, for an initial estimate we can be conservative and
> use something like 30000. If we're too conservative the SGI
> guys will tell us :)
OK, I initially thought you would head for a much larger
threshold. Not sure if 30000 is large enough for a full
scale NFS server though ;-> You conviced me that my idea
doesn't have any real advantage over yours, it essentialy
gets down the same result but yours is probably easier to
implement and we can also adopt the threshold dynamicaly
depending on the type of system. A big advantage is surely
that it is quite easy to tune this parameter for certain
more difficult cases.
^ permalink raw reply
* Re: [RFC/PATCH] "strict" ipv4 reassembly
From: Herbert Xu @ 2005-05-18 1:52 UTC (permalink / raw)
To: Thomas Graf; +Cc: David S. Miller, akepner, netdev
In-Reply-To: <20050518013712.GH13748@postel.suug.ch>
On Wed, May 18, 2005 at 03:37:12AM +0200, Thomas Graf wrote:
>
> OK, I initially thought you would head for a much larger
> threshold. Not sure if 30000 is large enough for a full
> scale NFS server though ;-> You conviced me that my idea
I think it's big enough. If it isn't it means that somebody
has reordered the packets by 30000 which I find hard to
believe :)
--
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
* [PATCH] NUMA aware allocation of transmit and receive buffers for e1000
From: Christoph Lameter @ 2005-05-18 1:56 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev, akpm
NUMA awareness for the e1000 driver. Allocate transmit and receive buffers
on the node of the device.
Signed-off-by: Christoph Lameter <christoph@lameter.com>
Signed-off-by: Justin M. Forbes <jmforbes@linuxtx.org>
Signed-off-by: Shai Fultheim <shai@scalex86.org>
Index: linux-2.6.11/drivers/net/e1000/e1000_main.c
===================================================================
--- linux-2.6.11.orig/drivers/net/e1000/e1000_main.c 2005-05-17 16:44:20.000000000 -0700
+++ linux-2.6.11/drivers/net/e1000/e1000_main.c 2005-05-17 17:47:43.000000000 -0700
@@ -120,8 +120,8 @@ int e1000_up(struct e1000_adapter *adapt
void e1000_down(struct e1000_adapter *adapter);
void e1000_reset(struct e1000_adapter *adapter);
int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
-int e1000_setup_tx_resources(struct e1000_adapter *adapter);
-int e1000_setup_rx_resources(struct e1000_adapter *adapter);
+int e1000_setup_tx_resources(struct e1000_adapter *adapter, int node);
+int e1000_setup_rx_resources(struct e1000_adapter *adapter, int node);
void e1000_free_tx_resources(struct e1000_adapter *adapter);
void e1000_free_rx_resources(struct e1000_adapter *adapter);
void e1000_update_stats(struct e1000_adapter *adapter);
@@ -513,6 +513,7 @@ e1000_probe(struct pci_dev *pdev,
netdev->mem_start = mmio_start;
netdev->mem_end = mmio_start + mmio_len;
netdev->base_addr = adapter->hw.io_base;
+ netdev->node = pcibus_to_node(pdev->bus);
adapter->bd_number = cards_found;
@@ -785,12 +786,12 @@ e1000_open(struct net_device *netdev)
/* allocate transmit descriptors */
- if((err = e1000_setup_tx_resources(adapter)))
+ if((err = e1000_setup_tx_resources(adapter, netdev->node)))
goto err_setup_tx;
/* allocate receive descriptors */
- if((err = e1000_setup_rx_resources(adapter)))
+ if((err = e1000_setup_rx_resources(adapter, netdev->node)))
goto err_setup_rx;
if((err = e1000_up(adapter)))
@@ -866,14 +867,14 @@ e1000_check_64k_bound(struct e1000_adapt
**/
int
-e1000_setup_tx_resources(struct e1000_adapter *adapter)
+e1000_setup_tx_resources(struct e1000_adapter *adapter, int node)
{
struct e1000_desc_ring *txdr = &adapter->tx_ring;
struct pci_dev *pdev = adapter->pdev;
int size;
size = sizeof(struct e1000_buffer) * txdr->count;
- txdr->buffer_info = vmalloc(size);
+ txdr->buffer_info = kmalloc_node(size, GFP_KERNEL, node);
if(!txdr->buffer_info) {
DPRINTK(PROBE, ERR,
"Unable to Allocate Memory for the Transmit descriptor ring\n");
@@ -891,7 +892,7 @@ e1000_setup_tx_resources(struct e1000_ad
setup_tx_desc_die:
DPRINTK(PROBE, ERR,
"Unable to Allocate Memory for the Transmit descriptor ring\n");
- vfree(txdr->buffer_info);
+ kfree(txdr->buffer_info);
return -ENOMEM;
}
@@ -1018,14 +1019,14 @@ e1000_configure_tx(struct e1000_adapter
**/
int
-e1000_setup_rx_resources(struct e1000_adapter *adapter)
+e1000_setup_rx_resources(struct e1000_adapter *adapter, int node)
{
struct e1000_desc_ring *rxdr = &adapter->rx_ring;
struct pci_dev *pdev = adapter->pdev;
int size;
size = sizeof(struct e1000_buffer) * rxdr->count;
- rxdr->buffer_info = vmalloc(size);
+ rxdr->buffer_info = kmalloc_node(size, GFP_KERNEL, node);
if(!rxdr->buffer_info) {
DPRINTK(PROBE, ERR,
"Unable to Allocate Memory for the Recieve descriptor ring\n");
@@ -1044,7 +1045,7 @@ e1000_setup_rx_resources(struct e1000_ad
setup_rx_desc_die:
DPRINTK(PROBE, ERR,
"Unble to Allocate Memory for the Recieve descriptor ring\n");
- vfree(rxdr->buffer_info);
+ kfree(rxdr->buffer_info);
return -ENOMEM;
}
@@ -1197,7 +1198,7 @@ e1000_free_tx_resources(struct e1000_ada
e1000_clean_tx_ring(adapter);
- vfree(adapter->tx_ring.buffer_info);
+ kfree(adapter->tx_ring.buffer_info);
adapter->tx_ring.buffer_info = NULL;
pci_free_consistent(pdev, adapter->tx_ring.size,
@@ -1279,7 +1280,7 @@ e1000_free_rx_resources(struct e1000_ada
e1000_clean_rx_ring(adapter);
- vfree(rx_ring->buffer_info);
+ kfree(rx_ring->buffer_info);
rx_ring->buffer_info = NULL;
pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma);
Index: linux-2.6.11/include/linux/netdevice.h
===================================================================
--- linux-2.6.11.orig/include/linux/netdevice.h 2005-05-17 16:44:20.000000000 -0700
+++ linux-2.6.11/include/linux/netdevice.h 2005-05-17 17:03:01.000000000 -0700
@@ -279,6 +279,7 @@ struct net_device
unsigned long mem_start; /* shared mem start */
unsigned long base_addr; /* device I/O address */
unsigned int irq; /* device IRQ number */
+ unsigned int node; /* device node number */
/*
* Some hardware also needs these fields, but they are not
^ permalink raw reply
* Re: [PATCH] NUMA aware allocation of transmit and receive buffers for e1000
From: Andrew Morton @ 2005-05-18 2:03 UTC (permalink / raw)
To: Christoph Lameter; +Cc: linux-kernel, netdev
In-Reply-To: <Pine.LNX.4.62.0505171854490.20408@graphe.net>
Christoph Lameter <christoph@graphe.net> wrote:
>
> NUMA awareness for the e1000 driver. Allocate transmit and receive buffers
> on the node of the device.
Hast thou any benchmarking results?
> - txdr->buffer_info = vmalloc(size);
> + txdr->buffer_info = kmalloc_node(size, GFP_KERNEL, node);
How come this is safe to do?
^ permalink raw reply
* Re: [PATCH] NUMA aware allocation of transmit and receive buffers for e1000
From: Andi Kleen @ 2005-05-18 2:05 UTC (permalink / raw)
To: Christoph Lameter; +Cc: netdev, akpm
In-Reply-To: <Pine.LNX.4.62.0505171854490.20408@graphe.net>
Christoph Lameter <christoph@graphe.net> writes:
> @@ -513,6 +513,7 @@ e1000_probe(struct pci_dev *pdev,
> netdev->mem_start = mmio_start;
> netdev->mem_end = mmio_start + mmio_len;
> netdev->base_addr = adapter->hw.io_base;
> + netdev->node = pcibus_to_node(pdev->bus);
I think it would be better to define a common helper (pdev_kmalloc ?)
for this that just takes the pdev and that can be defined to a nop for
!CONFIG_NUMA Kernels. This would avoid the bloat of the ->node
argument on non numa kernels and is a cleaner interface
too. pcibus_to_node() is just an array lookup and should be cheap
enough to redo.
-Andi
^ permalink raw reply
* [PATCH] Super TSO
From: David S. Miller @ 2005-05-18 2:24 UTC (permalink / raw)
To: netdev
Ok, this implements the idea Herbert and I kicked around last
week.
Basically, we build as large TSO segments as humanly possible.
Then we slice and dice them to fit the congestion and send
windows at transmit time.
It works remarkably well. Even application limited cases like
"scp" behave nicely.
During straight streaming tests like "bw_tcp", I see full
"65535 MOD mss" sized frames going out to my onboard tg3 card
once the congestion and send window grow large enough.
I did some cross-continent (San Francisco --> east coast of US)
transfers to make sure TSO stays on when packet drops occur and that
performance doesn't suffer compared to TSO being off. It all looks
fine so far.
There were many bugs discovered along the way. For example, the
old code would use the TSO mss to do nagle calculations. It also
would mess up the packet sizing for TSO when SACK blocks were
being advertised.
So we don't have to calculate this "(65535 - headers) % mss" thing
all the time, I keep a cache of three pieces of state. MSS, number
of SACKS being advertized, and if TSO is enabled or not. If any
of these change, we recalculate the packet building goal size.
I moved all of the "should we send" logic privately into the file
net/ipv4/tcp_output.c, and I am sure there are many simplifications
possible. There are several spurious tcp_current_mss() calls scattered
about in certain code paths as well. For example, some places would
call it in order to decide whether to call tcp_write_xmit() or not,
then tcp_write_xmit() does it once more. But there are call sites
that do not do this, so tcp_write_xmit() has to do it for those
cases.
Comments?
--- 1/include/linux/tcp.h.~1~ 2005-05-16 22:29:56.000000000 -0700
+++ 2/include/linux/tcp.h 2005-05-17 11:15:46.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 __pad0;
__u32 window_clamp; /* Maximal window to advertise */
__u32 rcv_ssthresh; /* Current window clamp */
--- 1/include/net/tcp.h.~1~ 2005-05-16 22:29:56.000000000 -0700
+++ 2/include/net/tcp.h 2005-05-17 16:44:32.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/include/net/sock.h.~1~ 2005-05-16 22:29:56.000000000 -0700
+++ 2/include/net/sock.h 2005-05-17 12:06:44.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/net/ipv4/tcp_output.c.~1~ 2005-05-16 22:29:56.000000000 -0700
+++ 2/net/ipv4/tcp_output.c 2005-05-17 19:14:23.000000000 -0700
@@ -141,11 +141,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 +361,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 +372,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
@@ -419,32 +419,11 @@ static inline void tcp_tso_set_push(stru
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 +433,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;
}
}
@@ -662,7 +641,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,59 +653,274 @@ 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;
+
+ if (tso_enabled)
+ ret |= (1 << 8);
+
+ return ret;
+}
-unsigned int tcp_current_mss(struct sock *sk, int large)
+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;
}
+/* 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) and if room at tail of skb is
+ * not enough to save something seriously (<32 for now).
+ *
+ * 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;
+}
+
+/* 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;
+}
+
+/* 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_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);
+}
+
+static inline unsigned int tso_size_limit(u32 window, unsigned int mss_now, unsigned int cwnd)
+{
+ u32 cwnd_len;
+
+ cwnd_len = mss_now * cwnd;
+ return min(window, cwnd_len);
+}
+
/* This routine writes packets to the network. It advances the
* send_head. This happens as incoming acks open up the remote
* window for us.
@@ -734,57 +928,167 @@ unsigned int tcp_current_mss(struct sock
* 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, 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;
+ if (unlikely(!skb))
+ return 0;
+
+ tso_segs = tcp_init_tso_segs(sk, skb);
+ cwnd_quota = tcp_cwnd_test(tp, skb);
+ sent_pkts = 0;
+
+ while (cwnd_quota) {
+ u32 end_seq, window_seq;
+
+ if (!tcp_nagle_test(tp, skb, mss_now,
+ (tcp_skb_is_last(sk, skb) ?
+ nonagle : TCP_NAGLE_PUSH)))
+ break;
+
+ end_seq = TCP_SKB_CB(skb)->end_seq;
+ window_seq = tp->snd_una + tp->snd_wnd;
+ if (skb->len > mss_now)
+ end_seq = TCP_SKB_CB(skb)->seq + mss_now;
+ if (after(end_seq, window_seq))
+ break;
+
+ BUG_ON(!tso_segs);
+
+ if (tso_segs > 1) {
+ u32 limit = tso_size_limit(window_seq -
+ TCP_SKB_CB(skb)->seq,
+ 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;
+ tcp_tso_set_push(skb);
+ 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)
+{
+ struct sk_buff *skb = sk->sk_send_head;
+
+ if (skb) {
+ if (!tcp_skb_is_last(sk, skb))
+ nonagle = TCP_NAGLE_PUSH;
+ if (tcp_write_xmit(sk, nonagle))
+ tcp_check_probe_timer(sk, tp);
+ }
+ tcp_cwnd_validate(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->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) {
+ u32 window_seq;
+
+ window_seq = tp->snd_una + tp->snd_wnd;
+ BUG_ON(!tso_segs);
+
+ if (tso_segs > 1) {
+ u32 limit = tso_size_limit(window_seq -
+ TCP_SKB_CB(skb)->seq,
+ 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;
+ tcp_tso_set_push(skb);
+ 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 +1345,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;
}
@@ -1671,13 +1969,6 @@ 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);
--- 1/net/ipv4/tcp.c.~1~ 2005-05-16 22:29:56.000000000 -0700
+++ 2/net/ipv4/tcp.c 2005-05-17 12:07:26.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-16 22:29:56.000000000 -0700
+++ 2/net/ipv4/tcp_input.c 2005-05-17 16:49:26.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)
@@ -3952,7 +3953,7 @@ static void tcp_new_space(struct sock *s
!(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-16 22:29:56.000000000 -0700
+++ 2/net/ipv4/tcp_ipv4.c 2005-05-17 11:27:14.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/ipv6/tcp_ipv6.c.~1~ 2005-05-16 22:29:56.000000000 -0700
+++ 2/net/ipv6/tcp_ipv6.c 2005-05-17 11:27:25.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;
^ permalink raw reply
* Re: [PATCH] TSO Reloaded
From: John Heffner @ 2005-05-18 2:26 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev
In-Reply-To: <20050504230731.12be1bc3.davem@davemloft.net>
Though it may be moot by now, I just ran some tests of my own with this
patch. This was on a dual 2.4 GHz Xeon booted with a UP kernel,
running iperf over an e1000 at a 1500 byte MTU. I measured idle CPU by
running a process which sits in a gettimeofday() loop. Numbers are CPU
utilization, all turned out +/- 1%.
No TSO: 86.6%
Old TSO: 61.0%
New TSO: 88.5%
-John
^ permalink raw reply
* Re: [PATCH] TSO Reloaded
From: David S. Miller @ 2005-05-18 2:28 UTC (permalink / raw)
To: jheffner; +Cc: netdev
In-Reply-To: <46332e5aa197db91aaf012cf140282b4@psc.edu>
From: John Heffner <jheffner@psc.edu>
Date: Tue, 17 May 2005 22:26:09 -0400
> Though it may be moot by now, I just ran some tests of my own with this
> patch. This was on a dual 2.4 GHz Xeon booted with a UP kernel,
> running iperf over an e1000 at a 1500 byte MTU. I measured idle CPU by
> running a process which sits in a gettimeofday() loop. Numbers are CPU
> utilization, all turned out +/- 1%.
>
> No TSO: 86.6%
> Old TSO: 61.0%
> New TSO: 88.5%
Yeah, TSO Reloaded really stinks. :-)
Try the "Super TSO" patch I just posted instead.
^ permalink raw reply
* Re: [PATCH] TSO Reloaded
From: John Heffner @ 2005-05-18 2:51 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev
In-Reply-To: <20050517.192829.71087792.davem@davemloft.net>
On May 17, 2005, at 10:28 PM, David S. Miller wrote:
> From: John Heffner <jheffner@psc.edu>
> Date: Tue, 17 May 2005 22:26:09 -0400
>
>> Though it may be moot by now, I just ran some tests of my own with
>> this
>> patch. This was on a dual 2.4 GHz Xeon booted with a UP kernel,
>> running iperf over an e1000 at a 1500 byte MTU. I measured idle CPU
>> by
>> running a process which sits in a gettimeofday() loop. Numbers are
>> CPU
>> utilization, all turned out +/- 1%.
>>
>> No TSO: 86.6%
>> Old TSO: 61.0%
>> New TSO: 88.5%
>
> Yeah, TSO Reloaded really stinks. :-)
>
> Try the "Super TSO" patch I just posted instead.
Interesting timing. :)
With the new patch I'm getting 78.0%.
-John
^ permalink raw reply
* Re: [PATCH] NUMA aware allocation of transmit and receive buffers for e1000
From: Christoph Lameter @ 2005-05-18 2:52 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-kernel, netdev
In-Reply-To: <20050517190343.2e57fdd7.akpm@osdl.org>
On Tue, 17 May 2005, Andrew Morton wrote:
> Christoph Lameter <christoph@graphe.net> wrote:
> >
> > NUMA awareness for the e1000 driver. Allocate transmit and receive buffers
> > on the node of the device.
>
> Hast thou any benchmarking results?
Yes, your honor. Just a second .... The patch has been around for a long
time.
No benchmarks results in my email archive. Would need to talk to some
folks tomorrow and maybe we would have to run some new
benchmarks.
> > - txdr->buffer_info = vmalloc(size);
> > + txdr->buffer_info = kmalloc_node(size, GFP_KERNEL, node);
>
> How come that this is safe to do
Because physically contiguous memory is usually better than virtually
contiguous memory? Any reason that physically contiguous memory will
break the driver?
^ permalink raw reply
* Re: [PATCH] NUMA aware allocation of transmit and receive buffers for e1000
From: David S. Miller @ 2005-05-18 2:57 UTC (permalink / raw)
To: christoph; +Cc: akpm, linux-kernel, netdev
In-Reply-To: <Pine.LNX.4.62.0505171941340.21153@graphe.net>
From: Christoph Lameter <christoph@lameter.com>
Subject: Re: [PATCH] NUMA aware allocation of transmit and receive buffers for e1000
Date: Tue, 17 May 2005 19:52:38 -0700 (PDT)
> > > - txdr->buffer_info = vmalloc(size);
> > > + txdr->buffer_info = kmalloc_node(size, GFP_KERNEL, node);
> >
> > How come that this is safe to do
>
> Because physically contiguous memory is usually better than virtually
> contiguous memory? Any reason that physically contiguous memory will
> break the driver?
The issue is whether size can end up being too large for
kmalloc() to satisfy, whereas vmalloc() would be able to
handle it.
^ permalink raw reply
* Re: [PATCH] TSO Reloaded
From: David S. Miller @ 2005-05-18 3:00 UTC (permalink / raw)
To: jheffner; +Cc: netdev
In-Reply-To: <0dd16bed0ea56242244bab0a7f1cf372@psc.edu>
From: John Heffner <jheffner@psc.edu>
Date: Tue, 17 May 2005 22:51:53 -0400
> On May 17, 2005, at 10:28 PM, David S. Miller wrote:
>
> > From: John Heffner <jheffner@psc.edu>
> > Date: Tue, 17 May 2005 22:26:09 -0400
> >
> >> No TSO: 86.6%
> >> Old TSO: 61.0%
> >> New TSO: 88.5%
> >
> > Yeah, TSO Reloaded really stinks. :-)
> >
> > Try the "Super TSO" patch I just posted instead.
>
> Interesting timing. :)
> With the new patch I'm getting 78.0%.
Thanks for testing.
I actually expected the new code to do better.
Splitting could be a little bit expensive, but
that only occurs at the beginning of the connection
as we ramp up the congestion and send window.
Afterwards, we should be able to release full unsplit
TSO frames onto the wire.
^ permalink raw reply
* Re: [PATCH] TSO Reloaded
From: John Heffner @ 2005-05-18 3:47 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev
In-Reply-To: <20050517.200015.55506861.davem@davemloft.net>
On May 17, 2005, at 11:00 PM, David S. Miller wrote:
> From: John Heffner <jheffner@psc.edu>
> Date: Tue, 17 May 2005 22:51:53 -0400
>
>> With the new patch I'm getting 78.0%.
>
> Thanks for testing.
>
> I actually expected the new code to do better.
> Splitting could be a little bit expensive, but
> that only occurs at the beginning of the connection
> as we ramp up the congestion and send window.
> Afterwards, we should be able to release full unsplit
> TSO frames onto the wire.
With different (larger than default) buffer sizes, I'm getting 63.4%.
Not surprising I guess.
-John
^ permalink raw reply
* Re: [PATCH] NUMA aware allocation of transmit and receive buffers for e1000
From: Christoph Lameter @ 2005-05-18 4:27 UTC (permalink / raw)
To: David S. Miller; +Cc: akpm, linux-kernel, netdev, shai
In-Reply-To: <20050517.195703.104034854.davem@davemloft.net>
On Tue, 17 May 2005, David S. Miller wrote:
> > Because physically contiguous memory is usually better than virtually
> > contiguous memory? Any reason that physically contiguous memory will
> > break the driver?
>
> The issue is whether size can end up being too large for
> kmalloc() to satisfy, whereas vmalloc() would be able to
> handle it.
Oww.. We need a NUMA aware vmalloc for this?
^ permalink raw reply
* Re: [PATCH] NUMA aware allocation of transmit and receive buffers for e1000
From: Andrew Morton @ 2005-05-18 4:58 UTC (permalink / raw)
To: Christoph Lameter; +Cc: davem, linux-kernel, netdev, shai
In-Reply-To: <Pine.LNX.4.62.0505172125210.22920@graphe.net>
Christoph Lameter <christoph@lameter.com> wrote:
>
> On Tue, 17 May 2005, David S. Miller wrote:
>
> > > Because physically contiguous memory is usually better than virtually
> > > contiguous memory? Any reason that physically contiguous memory will
> > > break the driver?
> >
> > The issue is whether size can end up being too large for
> > kmalloc() to satisfy, whereas vmalloc() would be able to
> > handle it.
>
> Oww.. We need a NUMA aware vmalloc for this?
I think the e1000 driver is being a bit insane there. I figure that
sizeof(struct e1000_buffer) is 28 on 64-bit, so even with 4k pagesize we'll
always succeed in being able to support a 32k/32 = 1024-entry Tx ring.
Is there any real-world reason for wanting larger ring sizes than that?
^ permalink raw reply
* Re: [PATCH] TSO Reloaded
From: David S. Miller @ 2005-05-18 5:59 UTC (permalink / raw)
To: jheffner; +Cc: netdev
In-Reply-To: <03e7252e3f5541302f25675360330b1e@psc.edu>
From: John Heffner <jheffner@psc.edu>
Date: Tue, 17 May 2005 23:47:48 -0400
> On May 17, 2005, at 11:00 PM, David S. Miller wrote:
>
> > I actually expected the new code to do better.
> > Splitting could be a little bit expensive, but
> > that only occurs at the beginning of the connection
> > as we ramp up the congestion and send window.
> > Afterwards, we should be able to release full unsplit
> > TSO frames onto the wire.
>
> With different (larger than default) buffer sizes, I'm getting 63.4%.
> Not surprising I guess.
Thanks for the data.
How long are your transfers? Just curious.
I think what I need to investigate is some kind of light cwnd
prediction. This, plus some TSO packet coalescing logic when we
undershoot, should do the trick.
But first I'll study the segmenting behavior of the current code. It
could be simply a matter of tweaking when we wake up the user when he
sleeps on the send buffer filling up.
^ permalink raw reply
* Re: tg3 crashes in scatter gather mode
From: raz ben jehuda @ 2005-05-18 7:48 UTC (permalink / raw)
To: netdev
In-Reply-To: <20050517.103853.104033596.davem@davemloft.net>
[-- Attachment #1: Type: text/plain, Size: 465 bytes --]
On Tue, 2005-05-17 at 20:38, David S.Miller wrote:
> From: raz ben jehuda <razb@bitband.com>
> Date: Tue, 17 May 2005 11:59:13 +0300
>
> > I am sending you my code. It belongs to my firm so please be
>
> No, that is unfair to force me and only me to be the only
> person to work on your bug report.
>
> If you can't post your code to the mailing lists so that
> other networking developers can help with this bug too,
> then sorry.
--
Raz
Long Live The Penguin
[-- Attachment #2: streamer_sg.tgz --]
[-- Type: application/x-compressed-tar, Size: 165372 bytes --]
^ permalink raw reply
* Re: [PATCH] NUMA aware allocation of transmit and receive buffers for e1000
From: Eric Dumazet @ 2005-05-18 7:49 UTC (permalink / raw)
To: Andi Kleen, Christoph Lameter; +Cc: netdev, akpm
In-Reply-To: <m1sm0l5lwa.fsf@muc.de>
Related question, is pci_alloc_consistent() already NUMA aware ?
Eric Dumazet
^ permalink raw reply
* Re: 2.6.12-rc4-mm2 - sleeping function called from invalid context at mm/slab.c:2502
From: Herbert Xu @ 2005-05-18 8:30 UTC (permalink / raw)
To: David S. Miller
Cc: Linux Audit Discussion, linux-kernel, netdev, Chris Wright
In-Reply-To: <20050517174300.GE27549@shell0.pdx.osdl.net>
[-- Attachment #1: Type: text/plain, Size: 850 bytes --]
Guys, please CC netdev on issues like this.
On Tue, May 17, 2005 at 05:43:00PM +0000, Chris Wright wrote:
>
> This has some issues w.r.t. truesize and socket buffer space. The trim
> is done to keep accounting sane, so we'd either have to trim ourselves
> or take into account the change in size. And ultimately, we'd still get
> trimmed by netlink, so the GFP issue is still there. Ideally, gfp_any()
> would really be _any_
The trimming is completely optional. That is, if the allocation fails
nothing bad will happen. So the solution is to simply use GFP_ATOMIC.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Cheers,
--
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
[-- Attachment #2: p --]
[-- Type: text/plain, Size: 277 bytes --]
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -673,7 +673,7 @@ int netlink_unicast(struct sock *ssk, st
int err;
long timeo;
- skb = netlink_trim(skb, gfp_any());
+ skb = netlink_trim(skb, GFP_ATOMIC);
timeo = sock_sndtimeo(ssk, nonblock);
retry:
^ permalink raw reply
* Re: [RFC/PATCH] "strict" ipv4 reassembly
From: Thomas Graf @ 2005-05-18 11:30 UTC (permalink / raw)
To: Herbert Xu; +Cc: David S. Miller, akepner, netdev
In-Reply-To: <20050518015213.GB28070@gondor.apana.org.au>
* Herbert Xu <20050518015213.GB28070@gondor.apana.org.au> 2005-05-18 11:52
> On Wed, May 18, 2005 at 03:37:12AM +0200, Thomas Graf wrote:
> >
> > OK, I initially thought you would head for a much larger
> > threshold. Not sure if 30000 is large enough for a full
> > scale NFS server though ;-> You conviced me that my idea
>
> I think it's big enough. If it isn't it means that somebody
> has reordered the packets by 30000 which I find hard to
> believe :)
I was thinking about some kind of nfs server with huge recv
buffers and increased limits receiving at 50kpps experiencing
a delayed fragment once in a while. Definitely a rare case
but not impossible ;->
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox