Netdev List
 help / color / mirror / Atom feed
* Re: tcp bw in 2.6
From: Linus Torvalds @ 2007-10-02  2:14 UTC (permalink / raw)
  To: Larry McVoy; +Cc: davem, wscott, netdev
In-Reply-To: <20071002005917.GB5480@bitmover.com>



On Mon, 1 Oct 2007, Larry McVoy wrote:
> 
> but the client looks like
> 
> connect(3, {sa_family=AF_INET, sin_port=htons(31235), sin_addr=inet_addr("10.3.9.1")}, 16) = 0
> read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1048576) = 2896
> read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1048576) = 1448
> read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1048576) = 2896
..

This is exactly what I'd expect if the machine is *not* under excessive 
load.

The system calls are fast enough that the latency for the TCP stack is 
roughly on the same scale as the time it takes to receive one new packet, 
so since a socket read will always return when it has any data (not until 
it has filled the whole buffer), you get exactly that "one or two packets" 
pattern.

If you'd be really CPU-limited or under load from other programs, you'd 
have more packets come in while you're in the read path, and you'd get 
bigger reads.

But do a tcpdump both ways, and see (for example) if the TCP window is 
much bigger going the other way.

		Linus

^ permalink raw reply

* Re: tcp bw in 2.6
From: Larry McVoy @ 2007-10-02  2:20 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Larry McVoy, davem, wscott, netdev
In-Reply-To: <alpine.LFD.0.999.0710011858400.3579@woody.linux-foundation.org>

On Mon, Oct 01, 2007 at 07:14:37PM -0700, Linus Torvalds wrote:
> 
> 
> On Mon, 1 Oct 2007, Larry McVoy wrote:
> > 
> > but the client looks like
> > 
> > connect(3, {sa_family=AF_INET, sin_port=htons(31235), sin_addr=inet_addr("10.3.9.1")}, 16) = 0
> > read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1048576) = 2896
> > read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1048576) = 1448
> > read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1048576) = 2896
> ..
> 
> This is exactly what I'd expect if the machine is *not* under excessive 
> load.

That's fine, but why is it that my trivial program can't do as well as 
dd | rsh dd?

A short summary is "can someone please post a test program that sources
and sinks data at the wire speed?"  because apparently I'm too old and
clueless to write such a thing.
-- 
---
Larry McVoy                lm at bitmover.com           http://www.bitkeeper.com

^ permalink raw reply

* Re: [PATCH 01/10] Preparatory refactoring part 1.
From: Patrick McHardy @ 2007-10-02  3:17 UTC (permalink / raw)
  To: Corey Hickey; +Cc: Linux Netdev List
In-Reply-To: <47015CB4.7000102@fatooh.org>

Corey Hickey wrote:
> Patrick McHardy wrote:
> 
>>> -    sch->qstats.drops++;
>>
>> A line in the changelog explaining that this was increased twice
>> would have been nice.
> 
> 
> Certainly; I think I didn't realize, when you originally pointed out the
> duplicate incrementing, that it was a bug in the original version and
> not in my patch. Otherwise, I would have sent it as a separate patch.


I didn't remember that :)

> If a note in this patch will suffice, though, I'll definitely do so.


Sure, a note in the changelog will be fine.

>>> +static struct
>>> +sk_buff *sfq_q_dequeue(struct sfq_sched_data *q)
>>
>>
>>
>> What is this function needed for?
> 
> 
> It gets used in sfq_change for moving packets from the old queue into
> the new one. In this case, we don't want to modify sch->q.qlen or
> sch->qstats.backlog, since those don't actually change.
> 
>          while ((skb = sfq_q_dequeue(q)) != NULL)
>                  sfq_q_enqueue(skb, &tmp, SFQ_TAIL);


I missed that, thanks for the explanation.


^ permalink raw reply

* Re: [PATCH 02/10] Preparatory refactoring part 2.
From: Patrick McHardy @ 2007-10-02  3:19 UTC (permalink / raw)
  To: Corey Hickey; +Cc: Linux Netdev List
In-Reply-To: <47015CBB.90109@fatooh.org>

Corey Hickey wrote:
> Patrick McHardy wrote:
> 
>>> +static void sfq_destroy(struct Qdisc *sch)
>>> +{
>>> +    struct sfq_sched_data *q = qdisc_priv(sch);
>>> +    sfq_q_destroy(q);
>>> +}
>>
>>
>> It does look pointless, after applying all patches sfq_destroy still
>> remains a simply wrapper around sfq_q_destroy.
> 
> 
> It does remain a wrapper, but both functions are used. It doesn't have
> to be this way, but I wanted to avoid duplicating code and I didn't see
> a better layout.
> 
> sfq_q_destroy is used in sfq_q_init if a kcalloc fails. sfq_q_init knows
> nothing about "struct Qdisc *sch", so it can't call sfq_destroy.


Thats fine, I didn't realize it was used without the struct Qdisc *
context. Changing sfq_destroy to sfq_q_destroy(qdisc_priv(sch));
would be a bit nicer though.

^ permalink raw reply

* Re: [PATCH 10/10] Use nested compat attributes to pass parameters.
From: Patrick McHardy @ 2007-10-02  3:21 UTC (permalink / raw)
  To: Corey Hickey; +Cc: Linux Netdev List
In-Reply-To: <47015CDA.60109@fatooh.org>

Corey Hickey wrote:
> Patrick McHardy wrote:
> 
>>> +    nest = RTA_NEST_COMPAT(skb, TCA_OPTIONS, sizeof(opt), &opt);
>>> +
>>> +    RTA_PUT_U32(skb, TCA_SFQ_QUANTUM, q->quantum);
>>> +    RTA_PUT_U32(skb, TCA_SFQ_PERTURB, q->perturb_period);
>>> +    RTA_PUT_U32(skb, TCA_SFQ_LIMIT,   q->limit);
>>> +    RTA_PUT_U32(skb, TCA_SFQ_DIVISOR, q->hash_divisor);
>>> +    RTA_PUT_U32(skb, TCA_SFQ_FLOWS,   q->depth);
>>>      RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
>>
>>
>>
>> This is wrong, RTA_NEST_COMPAT already dumps the structure.
> 
> 
> You mean that last line (RTA_PUT) is superfluous, right?


Exactly.

> Much thanks for the review. I'll make a new set of patches soon.


Thanks.

^ permalink raw reply

* Re: Removing DAD in IPv6
From: Xia Yang @ 2007-10-02  3:31 UTC (permalink / raw)
  To: netdev; +Cc: YOSHIFUJI Hideaki / 吉藤英明
In-Reply-To: <20071001.204448.130861285.yoshfuji@linux-ipv6.org>

Hi,

I just find out this IFA_F_NODAD was not in the kernel used in my test
bed which is 2.6.17. So I tried to modify the code in ipv6/addrconf.c by
myself to remove the DAD:

			if (!max_addresses ||
			    ipv6_count_addresses(in6_dev) < max_addresses)
				ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,
						    addr_type&IPV6_ADDR_SCOPE_MASK, 0);

			if (!ifp || IS_ERR(ifp)) {
			    in6_dev_put(in6_dev);
			    return;
			}
// --------New code ----------------
			if (!IS_ERR(ifp)) {
			    spin_lock_bh(&ifp->lock);
			    ifp->flags &= ~IFA_F_TENTATIVE;
			    spin_unlock_bh(&ifp->lock);
			
			    addrconf_join_solict(ifp->idev->dev, &ifp->addr);
			    ipv6_ifa_notify(RTM_NEWADDR, ifp);
			    //in6_ifa_put(ifp);
			    printk("New address configured.\n");
			}
// ----------end -------------------
			update_lft = create = 1;
			ifp->cstamp = jiffies;

			// addrconf_dad_start(ifp, RTF_ADDRCONF|RTF_PREFIX_RT);

However, even the new address is generated and assigned to the
interface, and I can read the address from the /proc interface, my first
few packets are eaten by the kernel. Only until after about 1 second,
then my packet can make its way out. Is kernel doing anything that
blocks the sending and receiving of packets during the time of DAD?
Thanks a lot!

Best Regards,

Xia Yang



On Mon, 2007-10-01 at 20:44 +0900, YOSHIFUJI Hideaki / 吉藤英明 wrote:
> In article <1191210807.25398.18.camel@orbit6> (at Mon, 01 Oct 2007 11:53:27 +0800), Xia Yang <xiayang@ntu.edu.sg> says:
> 
> > I would like to ask for help on how to remove or disable the DAD process
> > properly, as long as the node can send, receive and forward packets
> > immediately after a new IPv6 address is generated. Any pointer is
> > appreciated. Thanks a lot in advance!
> 
> IFA_F_NODAD address flag might help this.
> 
> --yoshfuji

^ permalink raw reply

* Re: How do queue-less virtual devices wake higher level senders?
From: David Miller @ 2007-10-02  3:44 UTC (permalink / raw)
  To: greearb; +Cc: netdev
In-Reply-To: <47018FBA.4030700@candelatech.com>

From: Ben Greear <greearb@candelatech.com>
Date: Mon, 01 Oct 2007 17:24:26 -0700

> David Miller wrote:
> > From: Ben Greear <greearb@candelatech.com>
> > Date: Mon, 01 Oct 2007 16:49:06 -0700
> > 
> >> For 'real' hardware, it seems that the netif_stop_queue and
> >> netif_wake_queue methods handle stopping and waking the
> >> higher level senders, but for virtual devices with no
> >> queues, how does this work?
> > 
> > They don't queue, there is nothing to stop or wakeup.
> 
> Ok, so if I have a UDP socket bound to an interface that has
> no queue, and yet I see the send portion of the queue being
> full in netstat, what does this mean?

The physical device sitting behind the virtual one is where
queue stop and wakeup operations might be occuring.

^ permalink raw reply

* Re: tcp bw in 2.6
From: David Miller @ 2007-10-02  3:50 UTC (permalink / raw)
  To: lm; +Cc: torvalds, wscott, netdev
In-Reply-To: <20071002022059.GE7037@bitmover.com>

From: lm@bitmover.com (Larry McVoy)
Date: Mon, 1 Oct 2007 19:20:59 -0700

> A short summary is "can someone please post a test program that sources
> and sinks data at the wire speed?"  because apparently I'm too old and
> clueless to write such a thing.

You're not showing us your test program so there is no way we
can help you out.

My initial inclination, even without that critical information,
is to ask whether you are setting any socket options in way?

In particular, SO_RCVLOWAT can have a large effect here, if you're
setting it to something, that would explain why dd is doing better.  A
lot of people link to "helper libraries" with interfaces to setup
sockets with all sorts of socket option settings by default, try not
using such things if possible.

You also shouldn't dork at all with the receive and send buffer sizes.
They are adjusted dynamically by the kernel as the window grows.  But
if you set them to specific values, this dynamic logic is turned off.

^ permalink raw reply

* Re: tcp bw in 2.6
From: Larry McVoy @ 2007-10-02  4:23 UTC (permalink / raw)
  To: David Miller; +Cc: lm, torvalds, wscott, netdev
In-Reply-To: <20071001.205050.66151815.davem@davemloft.net>

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

On Mon, Oct 01, 2007 at 08:50:50PM -0700, David Miller wrote:
> From: lm@bitmover.com (Larry McVoy)
> Date: Mon, 1 Oct 2007 19:20:59 -0700
> 
> > A short summary is "can someone please post a test program that sources
> > and sinks data at the wire speed?"  because apparently I'm too old and
> > clueless to write such a thing.
> 
> You're not showing us your test program so there is no way we
> can help you out.

Attached.  Drop it into an lmbench tree and build it.

> My initial inclination, even without that critical information,
> is to ask whether you are setting any socket options in way?

The only one I was playing with was SO_RCVBUF/SO_SNDBUF and I tried
disabling that and I tried playing with the read/write size.  Didn't
help.

> In particular, SO_RCVLOWAT can have a large effect here, if you're
> setting it to something, that would explain why dd is doing better.  A
> lot of people link to "helper libraries" with interfaces to setup
> sockets with all sorts of socket option settings by default, try not
> using such things if possible.

Agreed.  That was my first thought as well, I must have been doing 
something that messed up the defaults.  But you did get the strace
output, there wasn't anything weird there.

> You also shouldn't dork at all with the receive and send buffer sizes.
> They are adjusted dynamically by the kernel as the window grows.  But
> if you set them to specific values, this dynamic logic is turned off.

Yeah, dorking with those is left over from the bad old days of '95
when lmbench was first shipped.  But I turned that all off and no
difference.

So feel free to show me where I'm an idiot in the code, but if you
can't, then what would rock would be a little send.c / recv.c that
demonstrated filling the pipe.
-- 
---
Larry McVoy                lm at bitmover.com           http://www.bitkeeper.com

[-- Attachment #2: bytes_tcp.c --]
[-- Type: text/x-csrc, Size: 2278 bytes --]

/*
 * bytes_tcp.c - simple TCP bandwidth source/sink
 *
 *	server usage:	bytes_tcp -s
 *	client usage:	bytes_tcp hostname [msgsize]
 *
 * Copyright (c) 1994 Larry McVoy.  
 * Copyright (c) 2002 Carl Staelin.  Distributed under the FSF GPL with
 * additional restriction that results may published only if
 * (1) the benchmark is unmodified, and
 * (2) the version in the sccsid below is included in the report.
 * Support for this development by Sun Microsystems is gratefully acknowledged.
 */
char	*id = "$Id$\n";
#include "bench.h"
#define	XFER	(1024*1024)

int	server_main(int ac, char **av);
int	client_main(int ac, char **av);
void	source(int data);

void
transfer(int get, int server, char *buf)
{
	int	c;

	while ((get > 0) && (c = read(server, buf, XFER)) > 0) {
		get -= c;
	}
	if (c < 0) {
		perror("bytes_tcp: transfer: read failed");
		exit(4);
	}
}

/* ARGSUSED */
int
client_main(int ac, char **av)
{
	int	server;
	int	get = 256 << 20;
	char	buf[XFER];
	char*	usage = "usage: %s -remotehost OR %s remotehost [msgsize]\n";

	if (ac != 2 && ac != 3) {
		(void)fprintf(stderr, usage, av[0], av[0]);
		exit(0);
	}
	if (ac == 3) get = bytes(av[2]);
	server = tcp_connect(av[1], TCP_DATA+1, SOCKOPT_READ|SOCKOPT_REUSE);
	if (server < 0) {
		perror("bytes_tcp: could not open socket to server");
		exit(2);
	}
	transfer(get, server, buf);
	close(server);
	exit(0);
	/*NOTREACHED*/
}

void
child()
{
	wait(0);
	signal(SIGCHLD, child);
}

/* ARGSUSED */
int
server_main(int ac, char **av)
{
	int	data, newdata;

	signal(SIGCHLD, child);
	data = tcp_server(TCP_DATA+1, SOCKOPT_READ|SOCKOPT_WRITE|SOCKOPT_REUSE);
	for ( ;; ) {
		newdata = tcp_accept(data, SOCKOPT_WRITE|SOCKOPT_READ);
		switch (fork()) {
		    case -1:
			perror("fork");
			break;
		    case 0:
			source(newdata);
			exit(0);
		    default:
			close(newdata);
			break;
		}
	}
}

void
source(int data)
{
	char	buf[XFER];

	while (write(data, buf, sizeof(buf)) > 0);
}


int
main(int ac, char **av)
{
	char*	usage = "Usage: %s -s OR %s -serverhost OR %s serverhost [msgsize]\n";
	if (ac < 2 || 3 < ac) {
		fprintf(stderr, usage, av[0], av[0], av[0]);
		exit(1);
	}
	if (ac == 2 && !strcmp(av[1], "-s")) {
		if (fork() == 0) server_main(ac, av);
		exit(0);
	} else {
		client_main(ac, av);
	}
	return(0);
}

[-- Attachment #3: lib_tcp.c --]
[-- Type: text/x-csrc, Size: 5094 bytes --]

/*
 * tcp_lib.c - routines for managing TCP connections.
 *
 * Positive port/program numbers are RPC ports, negative ones are TCP ports.
 *
 * Copyright (c) 1994-1996 Larry McVoy.
 */
#define		_LIB /* bench.h needs this */
#include	"bench.h"

/*
 * Get a TCP socket, bind it, figure out the port,
 * and advertise the port as program "prog".
 *
 * XXX - it would be nice if you could advertise ascii strings.
 */
int
tcp_server(int prog, int rdwr)
{
	int	sock;
	struct	sockaddr_in s;

#ifdef	LIBTCP_VERBOSE
	fprintf(stderr, "tcp_server(%u, %u)\n", prog, rdwr);
#endif
	if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
		perror("socket");
		exit(1);
	}
	sock_optimize(sock, rdwr);
	bzero((void*)&s, sizeof(s));
	s.sin_family = AF_INET;
	if (prog < 0) {
		s.sin_port = htons(-prog);
	}
	if (bind(sock, (struct sockaddr*)&s, sizeof(s)) < 0) {
		perror("bind");
		exit(2);
	}
	if (listen(sock, 100) < 0) {
		perror("listen");
		exit(4);
	}
	if (prog > 0) {
#ifdef	LIBTCP_VERBOSE
		fprintf(stderr, "Server port %d\n", sockport(sock));
#endif
		(void)pmap_unset((u_long)prog, (u_long)1);
		if (!pmap_set((u_long)prog, (u_long)1, (u_long)IPPROTO_TCP,
		    (unsigned short)sockport(sock))) {
			perror("pmap_set");
			exit(5);
		}
	}
	return (sock);
}

/*
 * Unadvertise the socket
 */
int
tcp_done(int prog)
{
	if (prog > 0) {
		pmap_unset((u_long)prog, (u_long)1);
	}
	return (0);
}

/*
 * Accept a connection and return it
 */
int
tcp_accept(int sock, int rdwr)
{
	struct	sockaddr_in s;
	int	newsock, namelen;

	namelen = sizeof(s);
	bzero((void*)&s, namelen);

retry:
	if ((newsock = accept(sock, (struct sockaddr*)&s, &namelen)) < 0) {
		if (errno == EINTR)
			goto retry;
		perror("accept");
		exit(6);
	}
#ifdef	LIBTCP_VERBOSE
	fprintf(stderr, "Server newsock port %d\n", sockport(newsock));
#endif
	sock_optimize(newsock, rdwr);
	return (newsock);
}

/*
 * Connect to the TCP socket advertised as "prog" on "host" and
 * return the connected socket.
 *
 * Hacked Thu Oct 27 1994 to cache pmap_getport calls.  This saves
 * about 4000 usecs in loopback lat_connect calls.  I suppose we
 * should time gethostbyname() & pmap_getprot(), huh?
 */
int
tcp_connect(char *host, int prog, int rdwr)
{
	static	struct hostent *h;
	static	struct sockaddr_in s;
	static	u_short	save_port;
	static	u_long save_prog;
	static	char *save_host;
	int	sock;
	static	int tries = 0;

	if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
		perror("socket");
		exit(1);
	}
	if (rdwr & SOCKOPT_PID) {
		static	unsigned short port;
		struct sockaddr_in sin;

		if (!port) {
			port = (unsigned short)(getpid() << 4);
			if (port < 1024) {
				port += 1024;
			}
		}
		do {
			port++;
			bzero((void*)&sin, sizeof(sin));
			sin.sin_family = AF_INET;
			sin.sin_port = htons(port);
		} while (bind(sock, (struct sockaddr*)&sin, sizeof(sin)) == -1);
	}
#ifdef	LIBTCP_VERBOSE
	else {
		struct sockaddr_in sin;

		bzero((void*)&sin, sizeof(sin));
		sin.sin_family = AF_INET;
		if (bind(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
			perror("bind");
			exit(2);
		}
	}
	fprintf(stderr, "Client port %d\n", sockport(sock));
#endif
	sock_optimize(sock, rdwr);
	if (!h || host != save_host || prog != save_prog) {
		save_host = host;	/* XXX - counting on them not
					 * changing it - benchmark only.
					 */
		save_prog = prog;
		if (!(h = gethostbyname(host))) {
			perror(host);
			exit(2);
		}
		bzero((void *) &s, sizeof(s));
		s.sin_family = AF_INET;
		bcopy((void*)h->h_addr, (void *)&s.sin_addr, h->h_length);
		if (prog > 0) {
			save_port = pmap_getport(&s, prog,
			    (u_long)1, IPPROTO_TCP);
			if (!save_port) {
				perror("lib TCP: No port found");
				exit(3);
			}
#ifdef	LIBTCP_VERBOSE
			fprintf(stderr, "Server port %d\n", save_port);
#endif
			s.sin_port = htons(save_port);
		} else {
			s.sin_port = htons(-prog);
		}
	}
	if (connect(sock, (struct sockaddr*)&s, sizeof(s)) < 0) {
		if (errno == ECONNRESET || errno == ECONNREFUSED) {
			close(sock);
			if (++tries > 10) return(-1);
			return (tcp_connect(host, prog, rdwr));
		}
		perror("connect");
		exit(4);
	}
	tries = 0;
	return (sock);
}

#define	LIBTCP_VERBOSE
void
sock_optimize(int sock, int flags)
{
	return;
	if (flags & SOCKOPT_READ) {
		int	sockbuf = SOCKBUF;

		while (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &sockbuf,
		    sizeof(int))) {
			sockbuf >>= 1;
		}
#ifdef	LIBTCP_VERBOSE
		fprintf(stderr, "sockopt %d: RCV: %dK\n", sock, sockbuf>>10);
#endif
	}
	if (flags & SOCKOPT_WRITE) {
		int	sockbuf = SOCKBUF;

		while (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sockbuf,
		    sizeof(int))) {
			sockbuf >>= 1;
		}
#ifdef	LIBTCP_VERBOSE
		fprintf(stderr, "sockopt %d: SND: %dK\n", sock, sockbuf>>10);
#endif
	}
	if (flags & SOCKOPT_REUSE) {
		int	val = 1;
		if (setsockopt(sock, SOL_SOCKET,
		    SO_REUSEADDR, &val, sizeof(val)) == -1) {
			perror("SO_REUSEADDR");
		}
	}
}

int
sockport(int s)
{
	int	namelen;
	struct sockaddr_in sin;

	namelen = sizeof(sin);
	if (getsockname(s, (struct sockaddr *)&sin, &namelen) < 0) {
		perror("getsockname");
		return(-1);
	}
	return ((int)ntohs(sin.sin_port));
}

^ permalink raw reply

* [ofa-general] Re: [PATCH 2/3][NET_BATCH] net core use batching
From: Bill Fink @ 2007-10-02  4:25 UTC (permalink / raw)
  To: hadi
  Cc: randy.dunlap, Robert.Olsson, gaagaan, kumarkr,
	peter.p.waskiewicz.jr, shemminger, johnpol, herbert, jeff,
	rdreier, mcarlson, general, sri, jagana, mchan, netdev,
	David Miller, tgraf, kaber
In-Reply-To: <1191245440.4378.12.camel@localhost>

On Mon, 01 Oct 2007, jamal wrote:

> On Mon, 2007-01-10 at 00:11 -0400, Bill Fink wrote:
> 
> > Have you done performance comparisons for the case of using 9000-byte
> > jumbo frames?
> 
> I havent, but will try if any of the gige cards i have support it.
> 
> As a side note: I have not seen any useful gains or losses as the packet
> size approaches even 1500B MTU. For example, post about 256B neither the
> batching nor the non-batching give much difference in either throughput
> or cpu use. Below 256B, theres a noticeable gain for batching.
> Note, in the cases of my tests all 4 CPUs are in full-throttle UDP and
> so the occupancy of both the qdisc queue(s) and ethernet ring is
> constantly high. For example at 512B, the app is 80% idle on all 4 CPUs
> and we are hitting in the range of wire speed. We are at 90% idle at
> 1024B. This is the case with or without batching.  So my suspicion is
> that with that trend a 9000B packet will just follow the same pattern.

One reason I ask, is that on an earlier set of alternative batching
xmit patches by Krishna Kumar, his performance testing showed a 30 %
performance hit for TCP for a single process and a size of 4 KB, and
a performance hit of 5 % for a single process and a size of 16 KB
(a size of 8 KB wasn't tested).  Unfortunately I was too busy at the
time to inquire further about it, but it would be a major potential
concern for me in my 10-GigE network testing with 9000-byte jumbo
frames.  Of course the single process and 4 KB or larger size was
the only case that showed a significant performance hit in Krishna
Kumar's latest reported test results, so it might be acceptable to
just have a switch to disable the batching feature for that specific
usage scenario.  So it would be useful to know if your xmit batching
changes would have similar issues.

Also for your xmit batching changes, I think it would be good to see
performance comparisons for TCP and IP forwarding in addition to your
UDP pktgen tests, including various packet sizes up to and including
9000-byte jumbo frames.

						-Bill

^ permalink raw reply

* on a different note
From: Larry McVoy @ 2007-10-02  5:13 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Larry McVoy, davem, wscott, netdev

I do have a pretty nice cluster of linux boxes if you need lmbench results
or something like that.  Linux and the rest of the unix stuff for whatever
that is worth...

work ~/LMbench2/bin ls -1
alpha-glibc22-linux		# need to upgrade to debian 4
hppa-glibc23-linux
hppa-hpux11
ia64-glibc23-linux
ia64-hpux11
mips-glibc23-linux
mips-irix
powerpc-aix
powerpc-glibc23-linux
powerpc-macosx
sparc-glibc23-linux
sparc-solaris
x86-darwin8.10.1
x86-freebsd2
x86-freebsd3
x86-freebsd4
x86-freebsd5
x86-freebsd6
x86-glibc20-linux		# redhat 5.2
x86-glibc21-linux		# redhat 6.1
x86-glibc22-linux		# redhat 7.2
x86-glibc23-linux		# redhat 9
x86-glibc24-linux		# debian from here on down
x86-glibc25-linux
x86-glibc26-linux
x86-netbsd
x86-openbsd
x86-sco3.2v5.0.7		# ha!
x86-solaris
x86_64-glibc23-linux

-- 
---
Larry McVoy                lm at bitmover.com           http://www.bitkeeper.com

^ permalink raw reply

* RE: [PATCH 6/9] fs_enet: Be an of_platform device when CONFIG_PPC_CPM_NEW_BINDING is set.
From: Esben Haabendal @ 2007-10-02  7:10 UTC (permalink / raw)
  To: 'Scott Wood'; +Cc: netdev, linuxppc-dev
In-Reply-To: <20070920220121.GF28784@loki.buserror.net>

Hi Scott,

A minor error handling bug

> +	const u32 *data = of_get_property(np, "phy-handle", &len);
> +	if (!data || len != 4)
> +		return -EINVAL;
> +
> +	phynode = of_find_node_by_phandle(*data);
> +	if (!phynode)
> +		return -EINVAL;
> +
> +	mdionode = of_get_parent(phynode);
> +	if (!phynode)

if (!mdionode)

> +		goto out_put_phy;

Best regards,
Esben

^ permalink raw reply

* Re: [PATCH] rtnl: Simplify ASSERT_RTNL
From: Herbert Xu @ 2007-10-02  9:28 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netdev, oliver, Eric W. Biederman, linux-usb-devel, davem
In-Reply-To: <46FFC512.9060101@trash.net>

On Sun, Sep 30, 2007 at 05:47:30PM +0200, Patrick McHardy wrote:
>
> In the IPv6 case we're only changing the multicast list,
> so we're never calling into __dev_set_promiscuity.
> 
> I actually even added a comment about this :)
> 
>         /* Unicast addresses changes may only happen under the rtnl,
>          * therefore calling __dev_set_promiscuity here is safe.
>          */

Good point.  I should stop mentally blocking out comments when
I read code :)

I'm a bit uncomfortable with having a function (change_flags)
that's sometimes in a sleepable context and sometimes running
with BH disabled.

So how about splitting up the unicast/multicast entry points
as follows?

[NET]: Restore multicast-only __dev_mc_upload

As it is dev_set_rx_mode needs to cope with being called with
or without the RTNL.  This is rather confusing when it comes
to understanding what locks are being held at a particular
point.

Since the only path that calls it without the RTNL is in the
multicast code, we could avoid the confusion by splitting that
out.

This patch restores the old __dev_mc_upload as a multicast-only
variant of dev_set_rx_mode.  It also gets rid of the now-unused
__dev_set_rx_mod and makes dev_set_rx_mode static since it's
only used in net/core/dev.c.

As a side-effect this fixes the warning triggered by the
RTNL_ASSERT in __dev_set_promiscuity.

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
--
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 91cd3f3..e9a579e 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1356,8 +1356,6 @@ extern struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
 extern int		register_netdev(struct net_device *dev);
 extern void		unregister_netdev(struct net_device *dev);
 /* Functions used for secondary unicast and multicast support */
-extern void		dev_set_rx_mode(struct net_device *dev);
-extern void		__dev_set_rx_mode(struct net_device *dev);
 extern int		dev_unicast_delete(struct net_device *dev, void *addr, int alen);
 extern int		dev_unicast_add(struct net_device *dev, void *addr, int alen);
 extern int 		dev_mc_delete(struct net_device *dev, void *addr, int alen, int all);
diff --git a/net/core/dev.c b/net/core/dev.c
index 833f060..4cf985f 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -967,6 +967,8 @@ void dev_load(struct net *net, const char *name)
 		request_module("%s", name);
 }
 
+static void dev_set_rx_mode(struct net_device *dev);
+
 /**
  *	dev_open	- prepare an interface for use.
  *	@dev:	device to open
@@ -2775,7 +2777,7 @@ void dev_set_allmulti(struct net_device *dev, int inc)
  *	filtering it is put in promiscous mode while unicast addresses
  *	are present.
  */
-void __dev_set_rx_mode(struct net_device *dev)
+static void dev_set_rx_mode(struct net_device *dev)
 {
 	/* dev_open will call this function so the list will stay sane. */
 	if (!(dev->flags&IFF_UP))
@@ -2784,9 +2786,11 @@ void __dev_set_rx_mode(struct net_device *dev)
 	if (!netif_device_present(dev))
 		return;
 
-	if (dev->set_rx_mode)
+	if (dev->set_rx_mode) {
+		netif_tx_lock_bh(dev);
 		dev->set_rx_mode(dev);
-	else {
+		netif_tx_unlock_bh(dev);
+	} else {
 		/* Unicast addresses changes may only happen under the rtnl,
 		 * therefore calling __dev_set_promiscuity here is safe.
 		 */
@@ -2798,18 +2802,14 @@ void __dev_set_rx_mode(struct net_device *dev)
 			dev->uc_promisc = 0;
 		}
 
-		if (dev->set_multicast_list)
+		if (dev->set_multicast_list) {
+			netif_tx_lock_bh(dev);
 			dev->set_multicast_list(dev);
+			netif_tx_unlock_bh(dev);
+		}
 	}
 }
 
-void dev_set_rx_mode(struct net_device *dev)
-{
-	netif_tx_lock_bh(dev);
-	__dev_set_rx_mode(dev);
-	netif_tx_unlock_bh(dev);
-}
-
 int __dev_addr_delete(struct dev_addr_list **list, int *count,
 		      void *addr, int alen, int glbl)
 {
@@ -2885,11 +2885,9 @@ int dev_unicast_delete(struct net_device *dev, void *addr, int alen)
 
 	ASSERT_RTNL();
 
-	netif_tx_lock_bh(dev);
 	err = __dev_addr_delete(&dev->uc_list, &dev->uc_count, addr, alen, 0);
 	if (!err)
-		__dev_set_rx_mode(dev);
-	netif_tx_unlock_bh(dev);
+		dev_set_rx_mode(dev);
 	return err;
 }
 EXPORT_SYMBOL(dev_unicast_delete);
@@ -2911,11 +2909,9 @@ int dev_unicast_add(struct net_device *dev, void *addr, int alen)
 
 	ASSERT_RTNL();
 
-	netif_tx_lock_bh(dev);
 	err = __dev_addr_add(&dev->uc_list, &dev->uc_count, addr, alen, 0);
 	if (!err)
-		__dev_set_rx_mode(dev);
-	netif_tx_unlock_bh(dev);
+		dev_set_rx_mode(dev);
 	return err;
 }
 EXPORT_SYMBOL(dev_unicast_add);
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
index 896b0ca..be987d5 100644
--- a/net/core/dev_mcast.c
+++ b/net/core/dev_mcast.c
@@ -65,6 +65,30 @@
  */
 
 /*
+ *     Update the multicast list into the physical NIC controller.
+ */
+
+static void __dev_mc_upload(struct net_device *dev)
+{
+	/* Don't do anything till we up the interface
+	 * [dev_open will do this too so the list will
+	 * stay sane]
+	 */
+
+	if (!(dev->flags & IFF_UP))
+		return;
+
+	/* Devices with which have been detached don't get set. */
+	if (!netif_device_present(dev))
+		return;
+
+	if (dev->set_rx_mode)
+		dev->set_rx_mode(dev);
+	else if (dev->set_multicast_list)
+		dev->set_multicast_list(dev);
+}
+
+/*
  *	Delete a device level multicast
  */
 
@@ -81,7 +105,7 @@ int dev_mc_delete(struct net_device *dev, void *addr, int alen, int glbl)
 		 *	loaded filter is now wrong. Fix it
 		 */
 
-		__dev_set_rx_mode(dev);
+		__dev_mc_upload(dev);
 	}
 	netif_tx_unlock_bh(dev);
 	return err;
@@ -98,7 +122,7 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl)
 	netif_tx_lock_bh(dev);
 	err = __dev_addr_add(&dev->mc_list, &dev->mc_count, addr, alen, glbl);
 	if (!err)
-		__dev_set_rx_mode(dev);
+		__dev_mc_upload(dev);
 	netif_tx_unlock_bh(dev);
 	return err;
 }
@@ -140,7 +164,7 @@ int dev_mc_sync(struct net_device *to, struct net_device *from)
 		da = next;
 	}
 	if (!err)
-		__dev_set_rx_mode(to);
+		__dev_mc_upload(to);
 	netif_tx_unlock_bh(to);
 
 	return err;
@@ -177,7 +201,7 @@ void dev_mc_unsync(struct net_device *to, struct net_device *from)
 				  da->da_addr, da->da_addrlen, 0);
 		da = next;
 	}
-	__dev_set_rx_mode(to);
+	__dev_mc_upload(to);
 
 	netif_tx_unlock_bh(to);
 	netif_tx_unlock_bh(from);

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

^ permalink raw reply related

* Re: 2.6.23-rc8-mm2 - tcp_fastretrans_alert() WARNING
From: Ilpo Järvinen @ 2007-10-02 10:26 UTC (permalink / raw)
  To: Cedric Le Goater; +Cc: Andrew Morton, LKML, Netdev, David Miller
In-Reply-To: <4700BD57.1090404@free.fr>

On Mon, 1 Oct 2007, Cedric Le Goater wrote:

> got it !
> 
> r3-06.test.meiosys.com login: WARNING: at /home/legoater/linux/2.6.23-rc8-mm2/net/ipv4/tcp_input.c:2314 tcp_fastretrans_alert()
> 
> Call Trace:
>  <IRQ>  [<ffffffff8040fdc3>] tcp_ack+0xcd6/0x18af
[...snip...]
> 
> TCP 0

Hmm, so it's SACK then... 

> I wasn't doing any particular test on n/w so it took me a while to figure 
> out how I was triggering the WARNING. Apparently, this is happening when I 
> run ketchup, but not always. This test machine is behind many firewall & 
> routers so it might be a reason.
>
> I'm trying to get the WARNING and the tcpdump output for it but for the
> moment, it seems it's beyond my reach :/

I'm currently out of ideas where it could come from... so lets try 
brute-force checking as your test case is not very high-speed... This 
could hide it though... :-(

Please put the patch below on top of clean rc8-mm2 (it includes the patch
I gave you last time) and try to reproduce.... These counter bugs can
survive for sometime until !sacked_out condition occurs, so the patch
below tries to find that out when inconsisteny occurs for the first time 
regardless of sacked_out (I also removed some statics which hopefully 
reduces compiler inlining for easier reading of the output). I tried this 
myself (except for verify()s in frto funcs and minor printout 
modifications), didn't trigger for me.

-- 
 i.

---
 include/net/tcp.h     |    3 +
 net/ipv4/tcp_input.c  |   23 +++++++++--
 net/ipv4/tcp_ipv4.c   |  102 +++++++++++++++++++++++++++++++++++++++++++++++++
 net/ipv4/tcp_output.c |    6 ++-
 4 files changed, 128 insertions(+), 6 deletions(-)

diff --git a/include/net/tcp.h b/include/net/tcp.h
index 991ccdc..54a0d91 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -43,6 +43,9 @@
 
 #include <linux/seq_file.h>
 
+extern void tcp_verify_fackets(struct sock *sk);
+extern void tcp_print_queue(struct sock *sk);
+
 extern struct inet_hashinfo tcp_hashinfo;
 
 extern atomic_t tcp_orphan_count;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index e22ffe7..1d7367d 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1140,7 +1140,7 @@ static int tcp_check_dsack(struct tcp_sock *tp, struct sk_buff *ack_skb,
 	return dup_sack;
 }
 
-static int
+int
 tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_una)
 {
 	const struct inet_connection_sock *icsk = inet_csk(sk);
@@ -1160,6 +1160,8 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
 	int first_sack_index;
 
 	if (!tp->sacked_out) {
+		if (WARN_ON(tp->fackets_out))
+			tcp_print_queue(sk);
 		tp->fackets_out = 0;
 		tp->highest_sack = tp->snd_una;
 	}
@@ -1420,6 +1422,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
 			}
 		}
 	}
+	tcp_verify_fackets(sk);
 
 	/* Check for lost retransmit. This superb idea is
 	 * borrowed from "ratehalving". Event "C".
@@ -1632,13 +1635,14 @@ void tcp_enter_frto(struct sock *sk)
 	tcp_set_ca_state(sk, TCP_CA_Disorder);
 	tp->high_seq = tp->snd_nxt;
 	tp->frto_counter = 1;
+	tcp_verify_fackets(sk);
 }
 
 /* Enter Loss state after F-RTO was applied. Dupack arrived after RTO,
  * which indicates that we should follow the traditional RTO recovery,
  * i.e. mark everything lost and do go-back-N retransmission.
  */
-static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag)
+void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct sk_buff *skb;
@@ -1675,6 +1679,7 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag)
 		}
 	}
 	tcp_verify_left_out(tp);
+	tcp_verify_fackets(sk);
 
 	tp->snd_cwnd = tcp_packets_in_flight(tp) + allowed_segments;
 	tp->snd_cwnd_cnt = 0;
@@ -1753,6 +1758,7 @@ void tcp_enter_loss(struct sock *sk, int how)
 		}
 	}
 	tcp_verify_left_out(tp);
+	tcp_verify_fackets(sk);
 
 	tp->reordering = min_t(unsigned int, tp->reordering,
 					     sysctl_tcp_reordering);
@@ -2308,7 +2314,7 @@ static void tcp_mtup_probe_success(struct sock *sk, struct sk_buff *skb)
  * It does _not_ decide what to send, it is made in function
  * tcp_xmit_retransmit_queue().
  */
-static void
+void
 tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag)
 {
 	struct inet_connection_sock *icsk = inet_csk(sk);
@@ -2322,8 +2328,11 @@ tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag)
 	if (!tp->packets_out)
 		tp->sacked_out = 0;
 
-	if (WARN_ON(!tp->sacked_out && tp->fackets_out))
+	if (WARN_ON(!tp->sacked_out && tp->fackets_out)) {
+		printk(KERN_ERR "TCP %d\n", tcp_is_reno(tp));
+		tcp_print_queue(sk);
 		tp->fackets_out = 0;
+	}
 
 	/* Now state machine starts.
 	 * A. ECE, hence prohibit cwnd undoing, the reduction is required. */
@@ -2333,6 +2342,8 @@ tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag)
 	/* B. In all the states check for reneging SACKs. */
 	if (tp->sacked_out && tcp_check_sack_reneging(sk))
 		return;
+	
+	tcp_verify_fackets(sk);
 
 	/* C. Process data loss notification, provided it is valid. */
 	if ((flag&FLAG_DATA_LOST) &&
@@ -2572,7 +2583,7 @@ static u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb)
  * is before the ack sequence we can discard it as it's confirmed to have
  * arrived at the other end.
  */
-static int tcp_clean_rtx_queue(struct sock *sk, s32 *seq_rtt_p)
+int tcp_clean_rtx_queue(struct sock *sk, s32 *seq_rtt_p)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 	const struct inet_connection_sock *icsk = inet_csk(sk);
@@ -2694,6 +2705,8 @@ static int tcp_clean_rtx_queue(struct sock *sk, s32 *seq_rtt_p)
 			ca_ops->pkts_acked(sk, pkts_acked, rtt_us);
 		}
 	}
+	tcp_verify_fackets(sk);
+
 
 #if FASTRETRANS_DEBUG > 0
 	BUG_TRAP((int)tp->sacked_out >= 0);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 7fed0a6..8b18757 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -108,6 +108,108 @@ struct inet_hashinfo __cacheline_aligned tcp_hashinfo = {
 	.lhash_wait  = __WAIT_QUEUE_HEAD_INITIALIZER(tcp_hashinfo.lhash_wait),
 };
 
+void tcp_print_queue(struct sock *sk)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct sk_buff *skb;
+	char s[50+1];
+	char i[50+1];
+	int idx = 0;
+	u32 hs = tp->highest_sack;
+	
+	if (!tp->sacked_out)
+		hs = tp->snd_una;
+	
+	tcp_for_write_queue(skb, sk) {
+		if (skb == tcp_send_head(sk))
+			break;
+		
+		if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED) {
+			if (skb->len < tp->mss_cache)
+				s[idx] = 's';
+			else
+				s[idx] = 'S';
+		} else {
+			s[idx] = '-';
+		}
+		if ((TCP_SKB_CB(skb)->seq == hs) && (tp->fastpath_skb_hint == skb))
+			i[idx] = 'x';
+		else if (tp->fastpath_skb_hint == skb)
+			i[idx] = 'f';
+		else if (TCP_SKB_CB(skb)->seq == hs)
+			i[idx] = 'h';
+		else
+			i[idx] = ' ';
+			
+		if (++idx >= 50) {
+			s[idx] = 0;
+			i[idx] = 0;
+			printk(KERN_ERR "TCP wq(s) %s\n", s);
+			printk(KERN_ERR "TCP wq(i) %s\n", i);
+			idx = 0;
+		}
+	}
+	if (idx) {
+		s[idx] = '<';
+		s[idx+1] = 0;
+		i[idx] = '<';
+		i[idx+1] = 0;
+		printk(KERN_ERR "TCP wq(s) %s\n", s);
+		printk(KERN_ERR "TCP wq(i) %s\n", i);
+	}
+	printk(KERN_ERR "s%u f%u p%u seq: su%u hs%u sn%u (%u)\n",
+		tp->sacked_out, tp->fackets_out, tp->packets_out,
+		tp->snd_una, tp->highest_sack, tp->snd_nxt,
+		((tp->fastpath_skb_hint == NULL) ? 0 :
+			TCP_SKB_CB(tp->fastpath_skb_hint)->seq));
+}
+
+void tcp_verify_fackets(struct sock *sk)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct sk_buff *skb;
+	u32 fackets = 0;
+	int hisack_valid = 0;
+	int err = 0;
+	
+	if (tcp_is_reno(tp))
+		return;
+	
+	if (!tp->sacked_out) {
+		if (WARN_ON(tp->fackets_out))
+			err = 1;
+		else if (tp->fastpath_skb_hint == NULL)
+			return;
+	}
+	
+	/* ...expensive processing here... */
+	tcp_for_write_queue(skb, sk) {
+		if (skb == tcp_send_head(sk))
+			break;
+
+		if (tp->sacked_out && (TCP_SKB_CB(skb)->seq == tp->highest_sack)) {
+			hisack_valid = 1;
+			if (WARN_ON(tp->fackets_out != fackets + tcp_skb_pcount(skb)))
+				err = 1;
+		}
+
+		if (skb == tp->fastpath_skb_hint)
+			if (WARN_ON(fackets != tp->fastpath_cnt_hint))
+				err = 1;
+
+		if (WARN_ON((fackets > tp->fackets_out) && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)))
+			err = 1;
+
+		fackets += tcp_skb_pcount(skb);
+	}
+	
+	if (WARN_ON(tp->sacked_out && !hisack_valid))
+		err = 1;
+	
+	if (err)
+		tcp_print_queue(sk);
+}
+
 static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
 {
 	return inet_csk_get_port(&tcp_hashinfo, sk, snum,
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 6199abe..4c70caf 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -773,6 +773,8 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss
 			tcp_verify_left_out(tp);
 		}
 		tcp_adjust_fackets_out(tp, skb, diff);
+		
+		tcp_verify_fackets(sk);
 	}
 
 	/* Link BUFF into the send queue. */
@@ -1688,7 +1690,7 @@ u32 __tcp_select_window(struct sock *sk)
 }
 
 /* Attempt to collapse two adjacent SKB's during retransmission. */
-static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int mss_now)
+void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int mss_now)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct sk_buff *next_skb = tcp_write_queue_next(sk, skb);
@@ -1764,6 +1766,8 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m
 		if (tp->fastpath_skb_hint == next_skb)
 			tp->fastpath_skb_hint = skb;
 
+		tcp_verify_fackets(sk);
+
 		sk_stream_free_skb(sk, next_skb);
 	}
 }
-- 
1.5.0.6


^ permalink raw reply related

* Re: incorrect cksum with tcp/udp on lo with 2.6.20/2.6.21/2.6.22
From: Herbert Xu @ 2007-10-02 10:40 UTC (permalink / raw)
  To: Krzysztof Oledzki; +Cc: netdev
In-Reply-To: <Pine.LNX.4.64.0709241128490.26474@bizon.gios.gov.pl>

On Mon, Sep 24, 2007 at 11:44:19AM +0200, Krzysztof Oledzki wrote:
> 
> So, with DR mode, packet goes by the lo device (with bad checksum) and 
> then get redirected outside. Unfortunately, when it leaves host it has bad 
> checksum, too. :(

Did you check this by taking a tcpdump on an external host?
Doing a local tcpdump doesn't work as tcpdump won't show the
correct checksum if checksum offload is enabled.

If it's really sending a bogus checksum then it's a bug in
LVS.

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

* [PATCH] Fallback to ipv4 if we try to add join IPv4 multicast group via ipv4-mapped address.
From: Dmitry Baryshkov @ 2007-10-02  9:59 UTC (permalink / raw)
  To: linux-kernel, netdev

Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>

diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index ae98818..c70a87d 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -38,6 +38,7 @@
 #include <linux/times.h>
 #include <linux/net.h>
 #include <linux/in.h>
+#include <linux/igmp.h>
 #include <linux/in6.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
@@ -183,6 +184,17 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr)
 	struct ipv6_mc_socklist *mc_lst;
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	int err;
+	int addr_type = ipv6_addr_type(addr);
+
+	if (addr_type == IPV6_ADDR_MAPPED) {
+		__be32 v4addr = addr->s6_addr32[3];
+		struct ip_mreqn mreq;
+		mreq.imr_multiaddr.s_addr = v4addr;
+		mreq.imr_address.s_addr = INADDR_ANY;
+		mreq.imr_ifindex = ifindex;
+
+		return ip_mc_join_group(sk, &mreq);
+	}
 
 	if (!ipv6_addr_is_multicast(addr))
 		return -EINVAL;
@@ -256,6 +268,18 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct ipv6_mc_socklist *mc_lst, **lnk;
 
+	int addr_type = ipv6_addr_type(addr);
+
+	if (addr_type == IPV6_ADDR_MAPPED) {
+		__be32 v4addr = addr->s6_addr32[3];
+		struct ip_mreqn mreq;
+		mreq.imr_multiaddr.s_addr = v4addr;
+		mreq.imr_address.s_addr = INADDR_ANY;
+		mreq.imr_ifindex = ifindex;
+
+		return ip_mc_leave_group(sk, &mreq);
+	}
+
 	write_lock_bh(&ipv6_sk_mc_lock);
 	for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) {
 		if ((ifindex == 0 || mc_lst->ifindex == ifindex) &&


^ permalink raw reply related

* Re: tcp bw in 2.6
From: Herbert Xu @ 2007-10-02 10:52 UTC (permalink / raw)
  To: Larry McVoy; +Cc: torvalds, davem, wscott, netdev
In-Reply-To: <20071002005917.GB5480@bitmover.com>

Larry McVoy <lm@bitmover.com> wrote:
>
> One of my clients also has gigabit so I played around with just that
> one and it (itanium running hpux w/ broadcom gigabit) can push the load
> as well.  One weird thing is that it is dependent on the direction the
> data is flowing.  If the hp is sending then I get 46MB/sec, if linux is
> sending then I get 18MB/sec.  Weird.  Linux is debian, running 

First of all check the CPU load on both sides to see if either
of them is saturating.  If the CPU's fine then look at the tcpdump
output to see if both receivers are using the same window settings.

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

* Blackfin Ethernet MAC driver compile error
From: Kalle Pokki @ 2007-10-02 11:30 UTC (permalink / raw)
  To: linux-kernel, netdev, bryan.wu

The Blackfin Ethernet MAC driver does not compile. It seems the driver is
missing some pinmux defines.

  CC      drivers/net/bfin_mac.o
drivers/net/bfin_mac.c: In function 'setup_pin_mux':
drivers/net/bfin_mac.c:275: error: 'P_MII0' undeclared (first use in
this function)
drivers/net/bfin_mac.c:275: error: (Each undeclared identifier is
reported only once
drivers/net/bfin_mac.c:275: error: for each function it appears in.)
drivers/net/bfin_mac.c:279: error: implicit declaration of function
'peripheral_request_list'
drivers/net/bfin_mac.c:285: error: implicit declaration of function
'peripheral_free_list'
make[2]: *** [drivers/net/bfin_mac.o] Error 1
make[1]: *** [drivers/net] Error 2
make: *** [drivers] Error 2

^ permalink raw reply

* Re: [PATCH][E1000E] some cleanups
From: jamal @ 2007-10-02 12:25 UTC (permalink / raw)
  To: Kok, Auke; +Cc: Jeff Garzik, netdev
In-Reply-To: <4700549A.70409@intel.com>

On Sun, 2007-30-09 at 18:59 -0700, Kok, Auke wrote:

> the IDs are the only thing needed to enable all pci-e e1000 hardware.

I'll give it a whirl in the next few days. It failed as a module (with
e1000 compiled out), i will try to compile it in. I have access to the
hardware in quiet times - so it may be the weekend.

> by all means we need to have guys like you and Jeff test the commented IDs! I've
> been doing this myself and the e1000e driver goes to our labs for a period of
> testing from next week. Unfortunately they don't know how to break it that good as
> some of you guys ;)
> 
> I'll personally try to get an 82571EB tested on monday.

How did that go?

cheers,
jamal


^ permalink raw reply

* Re: [PATCH][TG3]Some cleanups
From: jamal @ 2007-10-02 12:37 UTC (permalink / raw)
  To: Michael Chan; +Cc: Matt Carlson, netdev
In-Reply-To: <1191284504.25892.129.camel@dell>

On Mon, 2007-01-10 at 17:21 -0700, Michael Chan wrote:

> Jamal, in tg3_enqueue_buggy(), we may have to call tg3_tso_bug() which
> will recursively call tg3_start_xmit_dma_bug() after segmenting the TSO
> packet into normal packets.  We need to restore the VLAN tag so that the
> GSO code will create the chain of segmented SKBs with the proper VLAN
> tag.

Excellent eye Michael.
The simplest solution seems to me to modify the definition of TG3_SKB_CB
as i did for e1000 from:
(struct tg3_tx_cbdata *)&((__skb)->cb[0])
to:
(struct tg3_tx_cbdata *)&((__skb)->cb[8])

that way the vlan tags are always present and no need to recreate them.
What do you think?

cheers,
jamal


^ permalink raw reply

* Re: [RFC PATCH v0.2] net driver: mpc52xx fec
From: Sascha Hauer @ 2007-10-02 12:49 UTC (permalink / raw)
  To: Domen Puncer; +Cc: linuxppc-embedded, netdev
In-Reply-To: <20070902074143.GB2642@nd47.coderock.org>


Hi Domen,

On Sun, Sep 02, 2007 at 09:41:43AM +0200, Domen Puncer wrote:
 + */
> +static void fec_start(struct net_device *dev)
> +{
> +	struct fec_priv *priv = netdev_priv(dev);
> +	struct mpc52xx_fec __iomem *fec = priv->fec;
> +	u32 rcntrl;
> +	u32 tcntrl;
> +	u32 tmp;
> +
> +	/* clear sticky error bits */
> +	tmp = FEC_FIFO_STATUS_ERR | FEC_FIFO_STATUS_UF | FEC_FIFO_STATUS_OF;
> +	out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status) & tmp);
> +	out_be32(&fec->tfifo_status, in_be32(&fec->tfifo_status) & tmp);
> +
> +	/* FIFOs will reset on fec_enable */
> +	out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_ENABLE_IS_RESET);
> +
> +	/* Set station address. */
> +	fec_set_paddr(dev, dev->dev_addr);
> +
> +	fec_set_multicast_list(dev);
> +
> +	/* set max frame len, enable flow control, select mii mode */
> +	rcntrl = FEC_RX_BUFFER_SIZE << 16;	/* max frame length */
> +	rcntrl |= FEC_RCNTRL_FCE;
> +	rcntrl |= MII_RCNTL_MODE;
> +	if (priv->duplex == DUPLEX_FULL)
> +		tcntrl = FEC_TCNTRL_FDEN;	/* FD enable */
> +	else {
> +		rcntrl |= FEC_RCNTRL_DRT;	/* disable Rx on Tx (HD) */
> +		tcntrl = 0;
> +	}
> +	out_be32(&fec->r_cntrl, rcntrl);
> +	out_be32(&fec->x_cntrl, tcntrl);
> +
> +	/* Clear any outstanding interrupt. */
> +	out_be32(&fec->ievent, 0xffffffff);
> +
> +	/* Enable interrupts we wish to service. */
> +	out_be32(&fec->imask, FEC_IMASK_ENABLE);


This disables phy interrupts.


> +static int fec_mdio_read(struct mii_bus *bus, int phy_id, int reg)
> +{
> +	struct fec_mdio_priv *priv = bus->priv;
> +	int tries = 100;
> +
> +	u32 request = FEC_MII_READ_FRAME;
> +	request |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
> +	request |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
> +
> +	out_be32(&priv->regs->mii_data, request);
> +
> +	/* wait for it to finish, this takes about 23 us on lite5200b */
> +	while (priv->completed == 0 && tries--)
> +		udelay(5);
> +
> +	priv->completed = 0;
> +
> +	if (tries == 0)
> +		return -ETIMEDOUT;

This does not work as expected. When a timeout occurs tries is -1 not 0,
so the test above will never trigger.
Using --tries instead of tries-- reveals another bug. We get a timeout
everytime now, because MII interrupts are accidently disabled in
fec_start().

We cannot use a waitqueue or similar for waiting for the mii transfer
because we are atomic here.
A simple fix is provided below. It removes the need for the interrupt
handler in the phy handling routines. Anyway, it might be better to fix
the phy layer not to use atomic contexts, so this patch might not be the
way to go.


Regards, 
  Sascha

 +
> +static int fec_mdio_probe(struct of_device *of, const struct of_device_id *match)
> +{
> +	struct device *dev = &of->dev;
>
>       [...]
>
> +	init_waitqueue_head(&priv->wq);

This waitqueue is never used. wake_up() is called in the interrupt
handler, but noone ever sleeps on the queue.


---
 drivers/net/fec_mpc52xx/fec.c     |    7 +---
 drivers/net/fec_mpc52xx/fec_phy.c |   59 +++++++-------------------------------
 2 files changed, 15 insertions(+), 51 deletions(-)

Index: linux-2.6.23-rc8/drivers/net/fec_mpc52xx/fec.c
===================================================================
--- linux-2.6.23-rc8.orig/drivers/net/fec_mpc52xx/fec.c
+++ linux-2.6.23-rc8/drivers/net/fec_mpc52xx/fec.c
@@ -265,7 +265,6 @@ static void fec_phy_hw_init(struct fec_p
 		return;
 
 	out_be32(&fec->mii_speed, priv->phy_speed);
-	out_be32(&fec->imask, in_be32(&fec->imask) | FEC_IMASK_MII);
 }
 
 static int fec_open(struct net_device *dev)
@@ -654,7 +653,7 @@ static void fec_hw_init(struct net_devic
 	out_be32(&fec->iaddr1, 0x00000000);	/* No individual filter */
 	out_be32(&fec->iaddr2, 0x00000000);	/* No individual filter */
 
-	/* set phy speed and enable MII interrupt
+	/* set phy speed.
 	 * this can't be done in phy driver, since it needs to be called
 	 * before fec stuff (even on resume) */
 	fec_phy_hw_init(priv);
@@ -730,8 +729,8 @@ static void fec_stop(struct net_device *
 	struct mpc52xx_fec __iomem *fec = priv->fec;
 	unsigned long timeout;
 
-	/* disable all but MII interrupt */
-	out_be32(&fec->imask, in_be32(&fec->imask) & FEC_IMASK_MII);
+	/* disable all interrupts */
+	out_be32(&fec->imask, 0);
 
 	/* Disable the rx task. */
 	bcom_disable(priv->rx_dmatsk);
Index: linux-2.6.23-rc8/drivers/net/fec_mpc52xx/fec_phy.c
===================================================================
--- linux-2.6.23-rc8.orig/drivers/net/fec_mpc52xx/fec_phy.c
+++ linux-2.6.23-rc8/drivers/net/fec_mpc52xx/fec_phy.c
@@ -18,29 +18,28 @@
 #include "fec.h"
 
 struct fec_mdio_priv {
-	int completed;
-	wait_queue_head_t wq;
 	struct mpc52xx_fec __iomem *regs;
-	int irq;
 };
 
 static int fec_mdio_read(struct mii_bus *bus, int phy_id, int reg)
 {
 	struct fec_mdio_priv *priv = bus->priv;
+	struct mpc52xx_fec __iomem *fec;
 	int tries = 100;
-
 	u32 request = FEC_MII_READ_FRAME;
+
+	fec = priv->regs;
+	out_be32(&fec->ievent, FEC_IEVENT_MII);
+
 	request |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
 	request |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
 
 	out_be32(&priv->regs->mii_data, request);
 
 	/* wait for it to finish, this takes about 23 us on lite5200b */
-	while (priv->completed == 0 && tries--)
+	while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries)
 		udelay(5);
 
-	priv->completed = 0;
-
 	if (tries == 0)
 		return -ETIMEDOUT;
 
@@ -50,9 +49,13 @@ static int fec_mdio_read(struct mii_bus 
 static int fec_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 data)
 {
 	struct fec_mdio_priv *priv = bus->priv;
+	struct mpc52xx_fec __iomem *fec;
 	u32 value = data;
 	int tries = 100;
 
+	fec = priv->regs;
+	out_be32(&fec->ievent, FEC_IEVENT_MII);
+
 	value |= FEC_MII_WRITE_FRAME;
 	value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
 	value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
@@ -60,38 +63,15 @@ static int fec_mdio_write(struct mii_bus
 	out_be32(&priv->regs->mii_data, value);
 
 	/* wait for request to finish */
-	while (priv->completed == 0 && tries--)
+	while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries)
 		udelay(5);
 
-	priv->completed = 0;
-
 	if (tries == 0)
 		return -ETIMEDOUT;
 
 	return 0;
 }
 
-static irqreturn_t fec_mdio_interrupt(int irq, void *dev_id)
-{
-	struct fec_mdio_priv *priv = dev_id;
-	struct mpc52xx_fec __iomem *fec;
-	int ievent;
-
-	fec = priv->regs;
-	ievent = in_be32(&fec->ievent);
-
-	ievent &= FEC_IEVENT_MII;
-	if (!ievent)
-		return IRQ_NONE;
-
-	out_be32(&fec->ievent, ievent);
-
-	priv->completed = 1;
-	wake_up(&priv->wq);
-
-	return IRQ_HANDLED;
-}
-
 static int fec_mdio_probe(struct of_device *of, const struct of_device_id *match)
 {
 	struct device *dev = &of->dev;
@@ -143,22 +123,12 @@ static int fec_mdio_probe(struct of_devi
 		goto out_free;
 	}
 
-	priv->irq = irq_of_parse_and_map(np, 0);
-	err = request_irq(priv->irq, &fec_mdio_interrupt, IRQF_DISABLED | IRQF_SHARED,
-	                "fec_mdio", priv);
-	if (err) {
-		printk(KERN_ERR "%s: interrupt request failed with %i\n", __func__, err);
-		goto out_unmap;
-	}
-
 	bus->id = res.start;
 	bus->priv = priv;
 
 	bus->dev = dev;
 	dev_set_drvdata(dev, bus);
 
-	init_waitqueue_head(&priv->wq);
-
 	/* set MII speed */
 	out_be32(&priv->regs->mii_speed, ((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1);
 
@@ -167,13 +137,10 @@ static int fec_mdio_probe(struct of_devi
 
 	err = mdiobus_register(bus);
 	if (err)
-		goto out_free_irq;
+		goto out_unmap;
 
 	return 0;
 
- out_free_irq:
-	free_irq(priv->irq, dev);
-	irq_dispose_mapping(priv->irq);
  out_unmap:
 	iounmap(priv->regs);
  out_free:
@@ -197,8 +164,6 @@ static int fec_mdio_remove(struct of_dev
 	mdiobus_unregister(bus);
 	dev_set_drvdata(dev, NULL);
 
-	free_irq(priv->irq, dev);
-	irq_dispose_mapping(priv->irq);
 	iounmap(priv->regs);
 	for (i=0; i<PHY_MAX_ADDR; i++)
 		if (bus->irq[i])

--
Pengutronix - Linux Solutions for Science and Industry
Entwicklungszentrum Nord     http://www.pengutronix.de

^ permalink raw reply

* [RFC/PATCH 0/3] UDP memory usage accounting (take 3)
From: Satoshi OSHIMA @ 2007-10-02 13:09 UTC (permalink / raw)
  To: David Miller, netdev
  Cc: Andi Kleen, Evgeniy Polyakov, Herbert Xu, ?? ??, Yumiko SUGITA,
	"??@RedHat"

This patch set try to introduce memory usage accounting for 
UDP(currently ipv4 only).

This is the second post of take 2 patch, because previous
post was broken by my MUA setting.

Only what I chage is my MUA setting. There is no code
change from take 2.

This patch set is for 2.6.23-rc8.

I appreciate your comment/test/feedback.

Satoshi Oshima

^ permalink raw reply

* [RFC/PATCH 1/3] UDP memory usage accounting (take 3): fix send buffer check
From: Satoshi OSHIMA @ 2007-10-02 13:11 UTC (permalink / raw)
  To: David Miller, netdev
  Cc: Andi Kleen, Evgeniy Polyakov, Herbert Xu, ?? ??, Yumiko SUGITA,
	??@RedHat
In-Reply-To: <4702430C.2080002@hitachi.com>

This patch introduces sndbuf size check before
memory allcation for send buffer.


signed-off-by: Satoshi Oshima <satoshi.oshima.fk@hitachi.com>
signed-off-by: Hideo Aoki <haoki@redhat.com>

Index: 2.6.23-rc7-udp_limit/net/ipv4/ip_output.c
===================================================================
--- 2.6.23-rc7-udp_limit.orig/net/ipv4/ip_output.c
+++ 2.6.23-rc7-udp_limit/net/ipv4/ip_output.c
@@ -1004,6 +1004,11 @@ alloc_new_skb:
 					frag = &skb_shinfo(skb)->frags[i];
 				}
 			} else if (i < MAX_SKB_FRAGS) {
+				if (atomic_read(&sk->sk_wmem_alloc) + PAGE_SIZE
+				    > 2 * sk->sk_sndbuf) {
+					err = -ENOBUFS;
+					goto error;
+				}
 				if (copy > PAGE_SIZE)
 					copy = PAGE_SIZE;
 				page = alloc_pages(sk->sk_allocation, 0);

^ permalink raw reply

* [RFC/PATCH 2/3] UDP memory usage accounting (take 3): accounting unit and variable
From: Satoshi OSHIMA @ 2007-10-02 13:13 UTC (permalink / raw)
  To: David Miller, netdev
  Cc: Andi Kleen, Evgeniy Polyakov, Herbert Xu, ?? ??, Yumiko SUGITA,
	??@RedHat
In-Reply-To: <4702430C.2080002@hitachi.com>

This patch introduces global variable for UDP memory accounting.
The unit is page.


signed-off-by: Satoshi Oshima <satoshi.oshima.fk@hitachi.com>
signed-off-by: Hideo Aoki <haoki@redhat.com>

Index: 2.6.23-rc3-udp_limit/include/net/sock.h
===================================================================
--- 2.6.23-rc3-udp_limit.orig/include/net/sock.h
+++ 2.6.23-rc3-udp_limit/include/net/sock.h
@@ -723,6 +723,13 @@ static inline int sk_stream_wmem_schedul
 	       sk_stream_mem_schedule(sk, size, 0);
 }
 
+#define SK_DATAGRAM_MEM_QUANTUM ((int)PAGE_SIZE)
+
+static inline int sk_datagram_pages(int amt)
+{
+	return DIV_ROUND_UP(amt, SK_DATAGRAM_MEM_QUANTUM);
+}
+
 /* Used by processes to "lock" a socket state, so that
  * interrupts and bottom half handlers won't change it
  * from under us. It essentially blocks any incoming
Index: 2.6.23-rc3-udp_limit/include/net/udp.h
===================================================================
--- 2.6.23-rc3-udp_limit.orig/include/net/udp.h
+++ 2.6.23-rc3-udp_limit/include/net/udp.h
@@ -65,6 +65,8 @@ extern rwlock_t udp_hash_lock;
 
 extern struct proto udp_prot;
 
+extern atomic_t udp_memory_allocated;
+
 struct sk_buff;
 
 /*
Index: 2.6.23-rc3-udp_limit/net/ipv4/proc.c
===================================================================
--- 2.6.23-rc3-udp_limit.orig/net/ipv4/proc.c
+++ 2.6.23-rc3-udp_limit/net/ipv4/proc.c
@@ -66,7 +66,8 @@ static int sockstat_seq_show(struct seq_
 		   fold_prot_inuse(&tcp_prot), atomic_read(&tcp_orphan_count),
 		   tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated),
 		   atomic_read(&tcp_memory_allocated));
-	seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot));
+	seq_printf(seq, "UDP: inuse %d mem %d\n", fold_prot_inuse(&udp_prot),
+		   atomic_read(&udp_memory_allocated));
 	seq_printf(seq, "UDPLITE: inuse %d\n", fold_prot_inuse(&udplite_prot));
 	seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot));
 	seq_printf(seq,  "FRAG: inuse %d memory %d\n", ip_frag_nqueues,
Index: 2.6.23-rc3-udp_limit/net/ipv4/udp.c
===================================================================
--- 2.6.23-rc3-udp_limit.orig/net/ipv4/udp.c
+++ 2.6.23-rc3-udp_limit/net/ipv4/udp.c
@@ -113,6 +113,10 @@ DEFINE_SNMP_STAT(struct udp_mib, udp_sta
 struct hlist_head udp_hash[UDP_HTABLE_SIZE];
 DEFINE_RWLOCK(udp_hash_lock);
 
+atomic_t udp_memory_allocated;
+
+EXPORT_SYMBOL(udp_memory_allocated);
+
 static int udp_port_rover;
 
 static inline int __udp_lib_lport_inuse(__u16 num, struct hlist_head udptable[])

^ permalink raw reply

* [RFC/PATCH 3/3] UDP memory usage accounting (take 3): measurement
From: Satoshi OSHIMA @ 2007-10-02 13:14 UTC (permalink / raw)
  To: David Miller, netdev
  Cc: Andi Kleen, Evgeniy Polyakov, Herbert Xu, ?? ??, Yumiko SUGITA,
	??@RedHat
In-Reply-To: <4702430C.2080002@hitachi.com>

This patch introduces memory usage measurement for UDP.


signed-off-by: Satoshi Oshima <satoshi.oshima.fk@hitachi.com>
signed-off-by: Hideo Aoki <haoki@redhat.com>

Index: 2.6.23-rc8-udp_limit/net/ipv4/ip_output.c
===================================================================
--- 2.6.23-rc8-udp_limit.orig/net/ipv4/ip_output.c
+++ 2.6.23-rc8-udp_limit/net/ipv4/ip_output.c
@@ -743,6 +743,8 @@ static inline int ip_ufo_append_data(str
 		/* specify the length of each IP datagram fragment*/
 		skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
 		skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
+		atomic_add(sk_datagram_pages(skb->truesize),
+			   sk->sk_prot->memory_allocated);
 		__skb_queue_tail(&sk->sk_write_queue, skb);
 
 		return 0;
@@ -924,6 +926,9 @@ alloc_new_skb:
 			}
 			if (skb == NULL)
 				goto error;
+			if (sk->sk_prot->memory_allocated)
+				atomic_add(sk_datagram_pages(skb->truesize),
+					   sk->sk_prot->memory_allocated);
 
 			/*
 			 *	Fill in the control structures
@@ -1023,6 +1028,8 @@ alloc_new_skb:
 				frag = &skb_shinfo(skb)->frags[i];
 				skb->truesize += PAGE_SIZE;
 				atomic_add(PAGE_SIZE, &sk->sk_wmem_alloc);
+				if (sk->sk_prot->memory_allocated)
+					atomic_inc(sk->sk_prot->memory_allocated);
 			} else {
 				err = -EMSGSIZE;
 				goto error;
@@ -1123,7 +1130,9 @@ ssize_t	ip_append_page(struct sock *sk, 
 			if (unlikely(!skb)) {
 				err = -ENOBUFS;
 				goto error;
-			}
+			} else if (sk->sk_prot->memory_allocated)
+				atomic_add(sk_datagram_pages(skb->truesize),
+					   sk->sk_prot->memory_allocated);
 
 			/*
 			 *	Fill in the control structures
@@ -1152,6 +1161,8 @@ ssize_t	ip_append_page(struct sock *sk, 
 			/*
 			 * Put the packet on the pending queue.
 			 */
+			atomic_add(sk_datagram_pages(skb->truesize),
+				   sk->sk_prot->memory_allocated);
 			__skb_queue_tail(&sk->sk_write_queue, skb);
 			continue;
 		}
@@ -1202,13 +1213,14 @@ int ip_push_pending_frames(struct sock *
 	struct iphdr *iph;
 	__be16 df = 0;
 	__u8 ttl;
-	int err = 0;
+	int err = 0, send_page_size;
 
 	if ((skb = __skb_dequeue(&sk->sk_write_queue)) == NULL)
 		goto out;
 	tail_skb = &(skb_shinfo(skb)->frag_list);
 
 	/* move skb->data to ip header from ext header */
+	send_page_size = sk_datagram_pages(skb->truesize);
 	if (skb->data < skb_network_header(skb))
 		__skb_pull(skb, skb_network_offset(skb));
 	while ((tmp_skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) {
@@ -1218,6 +1230,7 @@ int ip_push_pending_frames(struct sock *
 		skb->len += tmp_skb->len;
 		skb->data_len += tmp_skb->len;
 		skb->truesize += tmp_skb->truesize;
+		send_page_size += sk_datagram_pages(tmp_skb->truesize);
 		__sock_put(tmp_skb->sk);
 		tmp_skb->destructor = NULL;
 		tmp_skb->sk = NULL;
@@ -1269,6 +1282,8 @@ int ip_push_pending_frames(struct sock *
 	/* Netfilter gets whole the not fragmented skb. */
 	err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
 		      skb->dst->dev, dst_output);
+	if (sk->sk_prot->memory_allocated)
+		atomic_sub(send_page_size, sk->sk_prot->memory_allocated);
 	if (err) {
 		if (err > 0)
 			err = inet->recverr ? net_xmit_errno(err) : 0;
@@ -1298,9 +1313,15 @@ void ip_flush_pending_frames(struct sock
 {
 	struct inet_sock *inet = inet_sk(sk);
 	struct sk_buff *skb;
+	int num_flush_mem = 0;
 
-	while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL)
+	while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) {
+		num_flush_mem += sk_datagram_pages(skb->truesize);
 		kfree_skb(skb);
+	}
+
+	if (sk->sk_prot->memory_allocated)
+		atomic_sub(num_flush_mem, sk->sk_prot->memory_allocated);
 
 	inet->cork.flags &= ~IPCORK_OPT;
 	kfree(inet->cork.opt);
Index: 2.6.23-rc8-udp_limit/net/ipv4/udp.c
===================================================================
--- 2.6.23-rc8-udp_limit.orig/net/ipv4/udp.c
+++ 2.6.23-rc8-udp_limit/net/ipv4/udp.c
@@ -887,6 +887,9 @@ try_again:
 		err = ulen;
 
 out_free:
+	atomic_sub(sk_datagram_pages(skb->truesize),
+		   sk->sk_prot->memory_allocated);
+
 	skb_free_datagram(sk, skb);
 out:
 	return err;
@@ -894,6 +897,9 @@ out:
 csum_copy_err:
 	UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite);
 
+	atomic_sub(sk_datagram_pages(skb->truesize),
+		   sk->sk_prot->memory_allocated);
+
 	skb_kill_datagram(sk, skb, flags);
 
 	if (noblock)
@@ -1019,6 +1025,9 @@ int udp_queue_rcv_skb(struct sock * sk, 
 		goto drop;
 	}
 
+	atomic_add(sk_datagram_pages(skb->truesize),
+		   sk->sk_prot->memory_allocated);
+
 	UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag);
 	return 0;
 
@@ -1443,6 +1452,7 @@ struct proto udp_prot = {
 	.hash		   = udp_lib_hash,
 	.unhash		   = udp_lib_unhash,
 	.get_port	   = udp_v4_get_port,
+	.memory_allocated  = &udp_memory_allocated,
 	.obj_size	   = sizeof(struct udp_sock),
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt = compat_udp_setsockopt,
Index: 2.6.23-rc8-udp_limit/net/ipv4/af_inet.c
===================================================================
--- 2.6.23-rc8-udp_limit.orig/net/ipv4/af_inet.c
+++ 2.6.23-rc8-udp_limit/net/ipv4/af_inet.c
@@ -126,13 +126,41 @@ extern void ip_mc_drop_socket(struct soc
 static struct list_head inetsw[SOCK_MAX];
 static DEFINE_SPINLOCK(inetsw_lock);
 
+/**
+ *	__skb_queue_purge_and_sub_memory_allocated
+ *		- empty a list and subtruct memory allocation counter
+ *	@sk:   sk
+ *	@list: list to empty
+ *	Delete all buffers on an &sk_buff list and subtruct the
+ *	turesize of the sk_buff for memory accounting. Each buffer
+ *	is removed from the list and one reference dropped. This
+ *	function does not take the list lock and the caller must
+ *	hold the relevant locks to use it.
+ */
+void __skb_queue_purge_and_sub_memory_allocated(struct sock *sk,
+					struct sk_buff_head *list)
+{
+	struct sk_buff *skb;
+	int purged_skb_size = 0;
+	while ((skb = __skb_dequeue(list)) != NULL) {
+		purged_skb_size += sk_datagram_pages(skb->truesize);
+		kfree_skb(skb);
+	}
+	atomic_sub(purged_skb_size, sk->sk_prot->memory_allocated);
+}
+
 /* New destruction routine */
 
 void inet_sock_destruct(struct sock *sk)
 {
 	struct inet_sock *inet = inet_sk(sk);
 
-	__skb_queue_purge(&sk->sk_receive_queue);
+	if (sk->sk_prot->memory_allocated && sk->sk_type != SOCK_STREAM)
+		__skb_queue_purge_and_sub_memory_allocated(sk,
+				&sk->sk_receive_queue);
+	else
+		__skb_queue_purge(&sk->sk_receive_queue);
+
 	__skb_queue_purge(&sk->sk_error_queue);
 
 	if (sk->sk_type == SOCK_STREAM && sk->sk_state != TCP_CLOSE) {


^ 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