Netdev List
 help / color / mirror / Atom feed
* differences in skb allocation in fill_packet_ipv4 and fill_packet_ipv6
From: Lucian Adrian Grijincu @ 2009-08-31 16:08 UTC (permalink / raw)
  To: netdev

The skb is allocated differently in fill_packet_ipv4 and fill_packet_ipv6 (net/core/pktgen.c).


in fill_packet_ipv4():
        datalen = (odev->hard_header_len + 16) & ~0xf;
        skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen +
                        pkt_dev->pkt_overhead, GFP_ATOMIC);


but in fill_packet_ipv6():
        skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16 +
                        pkt_dev->pkt_overhead, GFP_ATOMIC);




hard_header_len was first added here in:
    7ac5459ec0f074022818af35c589b9e2b406d7c3
    [PKTGEN]: Respect hard_header_len of device.

A snip from the patch:
-	skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16, GFP_ATOMIC);
+	datalen = (odev->hard_header_len + 16) & ~0xf;
+	skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen, GFP_ATOMIC);


This patch only modifies fill_packet_ipv4(). Did someone forget to update
fill_packet_ipv6() as well or was this an ipv4-specific change (and why
would it be so)?

--
 .
..: Lucian

^ permalink raw reply

* Re: [PATCH resend] drop_monitor: fix trace_napi_poll_hit()
From: Neil Horman @ 2009-08-31 15:42 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: Xiao Guangrong, David Miller, Wei Yongjun, Netdev, LKML
In-Reply-To: <4A9BD13E.4040501@gmail.com>

On Mon, Aug 31, 2009 at 03:33:50PM +0200, Eric Dumazet wrote:
> Neil Horman a écrit :
> > I still see a large number of drivers that update dev->last_rx, although its
> > not all as I look through the list, so something definately seems amiss.
> 
> Some drivers still update dev->last_rx for their own needs, not a core
> network concern.
> 
> But a cleanup is certainly possible on few other drivers, about a dozen
> if I count correctly.
> 
> > 
> > If its not going to be consistently updated, why are still carrying that field
> > in dev?  Are we just waiting on someone to do the janitorial work to remove it?
> > If so, I can, and I'll fix up the drop monitor in the process, to use a private
> > timestamp.
> 
> We have to keep dev->last_rx for bonding use, so please use a private
> timestamp for drop monitor.
> 

Copy that, I'll submit a drop monitor patch for this sometime this week.  Thanks
for the heads up!
Neil

> Thanks
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply

* Re: Latest PreemptRT patch error on imx35
From: Tim Sander @ 2009-08-31 15:29 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: linux-rt-users, David S. Miller, Sascha Hauer, Greg Ungerer,
	netdev
In-Reply-To: <20090831132200.GA21836@pengutronix.de>

Hi

I just chrosschecked and build a kernel without a preempt RT patch. Two conclusions: 

* A 2.6.31-rc8-rt9 patched kernel is booting under preempt-rt with FEC-Etheret failing as reported or not at all with the configuration: preempt or no-preemption (server). 

* A 2.6.31-rc8 boots on the imx35 board.

Below a output dump of a failed boot of no-preemption 2.6.31-rc8-rt9 kernel

Best regards
Tim


Uncompressing Linux...................................................................................................... done, booting the kernel.
Linux version 2.6.31-rc8-rt9 (sander@dose) (gcc version 4.3.2 (OSELAS.Toolchain-1.99.3) ) #4 Mon Aug 31 13:33:49 CEST 2009
CPU: ARMv6-compatible processor [4117b363] revision 3 (ARMv6TEJ), cr=00c5387f
CPU: VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
Machine: Phytec Phycore pcm043
Memory policy: ECC disabled, Data cache writeback
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 32512
Kernel command line: jtag=on console=ttymxc0,115200 video=mx3fb:TX090 ip=172.19.169.71:172.19.169.15::255.255.0.0::: root=/dev/mtdblock3 rootfstype=jffs2 mtdparts=physmap-flash.0:256k(uboot)ro,128k(ubootenv),2048k(kernel),-(root);mxc_nand:
PID hash table entries: 512 (order: 9, 2048 bytes)
Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
Memory: 128MB = 128MB total
Memory: 126492KB available (2824K code, 265K data, 96K init, 0K highmem)
Hierarchical RCU implementation.
NR_IRQS:180
MXC GPIO hardware
MXC IRQ initialized
Console: colour dummy device 80x30
Calibrating delay loop... 398.95 BogoMIPS (lpj=1994752)
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
NET: Registered protocol family 16
L2X0 cache controller enabled
bio: create slab <bio-0> at 0
NET: Registered protocol family 2
IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
TCP established hash table entries: 4096 (order: 3, 32768 bytes)
TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
TCP: Hash tables configured (established 4096 bind 4096)
TCP reno registered
NET: Registered protocol family 1
JFFS2 version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
msgmni has been set to 247
alg: No test for stdrng (krng)
io scheduler noop registered (default)
Serial: IMX driver
imx-uart.0: ttymxc0 at MMIO 0x43f90000 (irq = 45) is a IMX
console [ttymxc0] enabled
imx-uart.1: ttymxc1 at MMIO 0x43f94000 (irq = 32) is a IMX
FEC Ethernet Driver
fec: PHY @ 0x0, ID 0x00221512 -- unknown PHY!
physmap platform flash device: 02000000 at a0000000
physmap-flash.0: Found 1 x16 devices at 0x0 in 16-bit bank
 Intel/Sharp Extended Query Table at 0x010A
 Intel/Sharp Extended Query Table at 0x010A
 Intel/Sharp Extended Query Table at 0x010A
 Intel/Sharp Extended Query Table at 0x010A
 Intel/Sharp Extended Query Table at 0x010A
Using buffer write method
Using auto-unlock on power-up/resume
cfi_cmdset_0001: Erase suspend on write enabled
mtd: partition size too small (0)
4 cmdlinepart partitions found on MTD device physmap-flash.0
Creating 4 MTD partitions on "physmap-flash.0":
0x000000000000-0x000000040000 : "uboot"
0x000000040000-0x000000060000 : "ubootenv"
0x000000060000-0x000000260000 : "kernel"
0x000000260000-0x000002000000 : "root"
mice: PS/2 mouse device common for all mice
Driver for 1-wire Dallas network protocol.
cpuidle: using governor ladder
TCP cubic registered
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
VFP support v0.3: implementor 41 architecture 1 part 20 variant b rev 3
drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
IP-Config: Complete:
     device=eth0, addr=172.19.169.71, mask=255.255.0.0, gw=255.255.255.255,
     host=172.19.169.71, domain=, nis-domain=(none),
     bootserver=172.19.169.15, rootserver=172.19.169.15, rootpath=
VFS: Mounted root (jffs2 filesystem) on device 31:3.
Freeing init memory: 96K
Unable to handle kernel paging request at virtual address de609800
pgd = c0004000
[de609800] *pgd=00000000
Internal error: Oops: 805 [#1]
Modules linked in:
CPU: 0    Not tainted  (2.6.31-rc8-rt9 #4)
PC is at __lru_cache_add+0x5c/0x84
LR is at add_to_page_cache_lru+0xa4/0xa8
pc : [<c006ace0>]    lr : [<c0062430>]    psr: a0000013
sp : c7819d04  ip : 00000190  fp : c7407648
r10: c740764c  r9 : 0000005b  r8 : 00100100
r7 : 00200200  r6 : 00000000  r5 : 00000002  r4 : c0305bc8
r3 : c78c0ea9  r2 : c78c0eaa  r1 : c0305d58  r0 : c0342760
Flags: NzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
Control: 00c5387d  Table: 80004008  DAC: 00000017
Process swapper (pid: 1, stack limit = 0xc7818268)
Stack: (0xc7819d04 to 0xc781a000)
9d00:          c0342760 00000000 00000004 0000005b c0342760 00000000 c0069ecc
9d20: c788c380 c7819d38 c74059b8 00000001 c787d9c0 00000004 c0344b78 c033c3f8
9d40: c7407700 00000003 00000000 00000000 00000000 c7407648 c787d9c0 c787d9c0
9d60: 00000000 c0069f4c 00000003 c787d9c0 00000000 c006a328 00000000 00000001
9d80: 00000001 c0062dfc 00000001 c042f580 c0061930 c7819df4 c7819e88 c74075b0
9da0: c787da00 00000001 ffffffff 00000fff 00000000 00000000 00000000 00000000
9dc0: 00000000 c7819ec8 c787d9c0 00000000 c7819df4 c0063bac c031c814 c031c5b0
9de0: 00000000 000000d0 c7819e88 00000001 c031cb60 00000000 00000080 c78821a0
9e00: 00000000 00000080 00000000 00000000 00000000 c7815cc0 c7819e38 c787d9c0
9e20: fffffdee c7819ec8 c7819f18 c0088754 00000000 00000000 00000004 00000000
9e40: 00000000 00000001 ffffffff c787d9c0 00000000 00000000 00000000 00000000
9e60: c7815cc0 00000000 00000000 00000000 00000000 c7815cc0 c0049aac c7819e7c
9e80: c7819e7c c008498c 00000000 00000000 c031c5b0 c79abde0 c78028f0 000f4240
9ea0: 00000080 c7815cc0 c02ff9d0 c7815cc0 00000000 00000000 ffffffff 00000000
9ec0: c7824000 c004e0f8 c78821a0 00000080 00000017 c787d9c0 c78821a0 c7819f18
9ee0: c78821a0 00000080 c7819f78 c02fb8c4 00000000 c00893c8 fffffeff ffffffff
9f00: c7819f18 00000000 000089ed c78821a0 c02fb838 c008dad8 00000000 00000000
9f20: c7819f78 c78821a0 c74075b0 c008dbfc c78821a0 00000080 00000004 c02fb848
9f40: c7818000 c008e36c 00000000 00000000 c7819f60 c02a2740 c02fb8c4 c02fb838
9f60: 00000000 00000000 00000000 00000000 00000000 c0023a70 00000000 00000000
9f80: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
9fa0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
9fc0: 00000000 c02fb8c4 c031cbd4 00000000 00000000 c0020514 c001bfa8 c001bfa8
9fe0: c001bfa8 c0008464 00000000 00000000 00000000 c002179c fffbfef1 ddcfe9fd
[<c006ace0>] (__lru_cache_add+0x5c/0x84) from [<0000005b>] (0x5b)
Code: e794200c e2823001 e2822002 e3530008 (e7810102)
---[ end trace bb332da858e3d4c4 ]---
Kernel panic - not syncing: Attempted to kill init!
[<c0025618>] (unwind_backtrace+0x0/0xe4) from [<c0246bcc>] (panic+0x3c/0x120)
[<c0246bcc>] (panic+0x3c/0x120) from [<c003913c>] (forget_original_parent+0x240/0x278)
[<c003913c>] (forget_original_parent+0x240/0x278) from [<c0039188>] (exit_notify+0x14/0x154)
[<c0039188>] (exit_notify+0x14/0x154) from [<c00393c4>] (do_exit+0xfc/0x294)
[<c00393c4>] (do_exit+0xfc/0x294) from [<c0024488>] (die+0xac/0xbc)
[<c0024488>] (die+0xac/0xbc) from [<c0026670>] (__do_kernel_fault+0x70/0x80)
[<c0026670>] (__do_kernel_fault+0x70/0x80) from [<c00268b4>] (do_translation_fault+0x6c/0x80)
[<c00268b4>] (do_translation_fault+0x6c/0x80) from [<c0020254>] (do_DataAbort+0x34/0x98)
[<c0020254>] (do_DataAbort+0x34/0x98) from [<c0020a4c>] (__dabt_svc+0x4c/0x60)
Exception stack(0xc7819cb8 to 0xc7819d00)
9ca0:                                                       c0342760 c0305d58
9cc0: c78c0eaa c78c0ea9 c0305bc8 00000002 00000000 00200200 00100100 0000005b
9ce0: c740764c c7407648 00000190 c7819d04 c0062430 c006ace0 a0000013 ffffffff
[<c0020a4c>] (__dabt_svc+0x4c/0x60) from [<c006ace0>] (__lru_cache_add+0x5c/0x84)
[<c006ace0>] (__lru_cache_add+0x5c/0x84) from [<0000005b>] (0x5b)

__lru_cache_add+0x5c/0x84
LR is at add_to_page_cache_lru+0xa4/0xa8
pc : [<c006ace0>]    lr : [<c0062430>]    psr: a0000013
sp : c7819d04  ip : 00000190  fp : c7407648
r10: c740764c  r9 : 0000005b  r8 : 00100100
r7 : 00200200  r6 : 00000000  r5 : 00000002  r4 : c0305bc8
r3 : c78c0ea9  r2 : c78c0eaa  r1 : c0305d58  r0 : c0342760
Flags: NzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
Control: 00c5387d  Table: 80004008  DAC: 00000017
Process swapper (pid: 1, stack limit = 0xc7818268)
Stack: (0xc7819d04 to 0xc781a000)
9d00:          c0342760 00000000 00000004 0000005b c0342760 00000000 c0069ecc
9d20: c788c380 c7819d38 c74059b8 00000001 c787d9c0 00000004 c0344b78 c033c3f8
9d40: c7407700 00000003 00000000 00000000 00000000 c7407648 c787d9c0 c787d9c0
9d60: 00000000 c0069f4c 00000003 c787d9c0 00000000 c006a328 00000000 00000001
9d80: 00000001 c0062dfc 00000001 c042f580 c0061930 c7819df4 c7819e88 c74075b0
9da0: c787da00 00000001 ffffffff 00000fff 00000000 00000000 00000000 00000000
9dc0: 00000000 c7819ec8 c787d9c0 00000000 c7819df4 c0063bac c031c814 c031c5b0
9de0: 00000000 000000d0 c7819e88 00000001 c031cb60 00000000 00000080 c78821a0
9e00: 00000000 00000080 00000000 00000000 00000000 c7815cc0 c7819e38 c787d9c0
9e20: fffffdee c7819ec8 c7819f18 c0088754 00000000 00000000 00000004 00000000
9e40: 00000000 00000001 ffffffff c787d9c0 00000000 00000000 00000000 00000000
9e60: c7815cc0 00000000 00000000 00000000 00000000 c7815cc0 c0049aac c7819e7c
9e80: c7819e7c c008498c 00000000 00000000 c031c5b0 c79abde0 c78028f0 000f4240
9ea0: 00000080 c7815cc0 c02ff9d0 c7815cc0 00000000 00000000 ffffffff 00000000
9ec0: c7824000 c004e0f8 c78821a0 00000080 00000017 c787d9c0 c78821a0 c7819f18
9ee0: c78821a0 00000080 c7819f78 c02fb8c4 00000000 c00893c8 fffffeff ffffffff
9f00: c7819f18 00000000 000089ed c78821a0 c02fb838 c008dad8 00000000 00000000
9f20: c7819f78 c78821a0 c74075b0 c008dbfc c78821a0 00000080 00000004 c02fb848
9f40: c7818000 c008e36c 00000000 00000000 c7819f60 c02a2740 c02fb8c4 c02fb838
9f60: 00000000 00000000 00000000 00000000 00000000 c0023a70 00000000 00000000
9f80: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
9fa0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
9fc0: 00000000 c02fb8c4 c031cbd4 00000000 00000000 c0020514 c001bfa8 c001bfa8
9fe0: c001bfa8 c0008464 00000000 00000000 00000000 c002179c fffbfef1 ddcfe9fd
[<c006ace0>] (__lru_cache_add+0x5c/0x84) from [<0000005b>] (0x5b)
Code: e794200c e2823001 e2822002 e3530008 (e7810102)
---[ end trace bb332da858e3d4c4 ]---
Kernel panic - not syncing: Attempted to kill init!
[<c0025618>] (unwind_backtrace+0x0/0xe4) from [<c0246bcc>] (panic+0x3c/0x120)
[<c0246bcc>] (panic+0x3c/0x120) from [<c003913c>] (forget_original_parent+0x240/0x278)
[<c003913c>] (forget_original_parent+0x240/0x278) from [<c0039188>] (exit_notify+0x14/0x154)
[<c0039188>] (exit_notify+0x14/0x154) from [<c00393c4>] (do_exit+0xfc/0x294)
[<c00393c4>] (do_exit+0xfc/0x294) from [<c0024488>] (die+0xac/0xbc)
[<c0024488>] (die+0xac/0xbc) from [<c0026670>] (__do_kernel_fault+0x70/0x80)
[<c0026670>] (__do_kernel_fault+0x70/0x80) from [<c00268b4>] (do_translation_fault+0x6c/0x80)
[<c00268b4>] (do_translation_fault+0x6c/0x80) from [<c0020254>] (do_DataAbort+0x34/0x98)
[<c0020254>] (do_DataAbort+0x34/0x98) from [<c0020a4c>] (__dabt_svc+0x4c/0x60)
Exception stack(0xc7819cb8 to 0xc7819d00)
9ca0:                                                       c0342760 c0305d58
9cc0: c78c0eaa c78c0ea9 c0305bc8 00000002 00000000 00200200 00100100 0000005b
9ce0: c740764c c7407648 00000190 c7819d04 c0062430 c006ace0 a0000013 ffffffff
[<c0020a4c>] (__dabt_svc+0x4c/0x60) from [<c006ace0>] (__lru_cache_add+0x5c/0x84)
[<c006ace0>] (__lru_cache_add+0x5c/0x84) from [<0000005b>] (0x5b)
--
To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCHv5 3/3] vhost_net: a kernel-level virtio server
From: Arnd Bergmann @ 2009-08-31 15:23 UTC (permalink / raw)
  To: Xin, Xiaohui
  Cc: mst@redhat.com, netdev@vger.kernel.org,
	virtualization@lists.linux-foundation.org, kvm@vger.kernel.org,
	linux-kernel@vger.kernel.org, mingo@elte.hu, linux-mm@kvack.org,
	akpm@linux-foundation.org, hpa@zytor.com,
	gregory.haskins@gmail.com
In-Reply-To: <C85CEDA13AB1CF4D9D597824A86D2B9006AEB944B8@PDSMSX501.ccr.corp.intel.com>

On Monday 31 August 2009, Xin, Xiaohui wrote:
> 
> Hi, Michael
> That's a great job. We are now working on support VMDq on KVM, and since the VMDq hardware presents L2 sorting
> based on MAC addresses and VLAN tags, our target is to implement a zero copy solution using VMDq.

I'm also interested in helping there, please include me in the discussions.

> We stared
> from the virtio-net architecture. What we want to proposal is to use AIO combined with direct I/O:
> 1) Modify virtio-net Backend service in Qemu to submit aio requests composed from virtqueue.

right, that sounds useful.

> 2) Modify TUN/TAP device to support aio operations and the user space buffer directly mapping into the host kernel.
> 3) Let a TUN/TAP device binds to single rx/tx queue from the NIC.

I don't think we should do that with the tun/tap driver. By design, tun/tap is a way to interact with the
networking stack as if coming from a device. The only way this connects to an external adapter is through
a bridge or through IP routing, which means that it does not correspond to a specific NIC.

I have worked on a driver I called 'macvtap' in lack of a better name, to add a new tap frontend to
the 'macvlan' driver. Since macvlan lets you add slaves to a single NIC device, this gives you a direct
connection between one or multiple tap devices to an external NIC, which works a lot better than when
you have a bridge inbetween. There is also work underway to add a bridging capability to macvlan, so
you can communicate directly between guests like you can do with a bridge.

Michael's vhost_net can plug into the same macvlan infrastructure, so the work is complementary.

> 4) Modify the net_dev and skb structure to permit allocated skb to use user space directly mapped payload
> buffer address rather then kernel allocated.

yes.

> As zero copy is also your goal, we are interested in what's in your mind, and would like to collaborate with you if possible.
> BTW, we will send our VMDq write-up very soon.

Ok, cool.

	Arnd <><

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* Re: [patch] ipvs: Use atomic operations atomicly
From: Simon Horman @ 2009-08-31 14:49 UTC (permalink / raw)
  To: Patrick McHardy
  Cc: lvs-devel, netdev, netfilter-devel, 홍신 shin hong,
	David Miller
In-Reply-To: <4A9BC082.3090804@trash.net>

On Mon, Aug 31, 2009 at 02:22:26PM +0200, Patrick McHardy wrote:
> Simon Horman wrote:
> > A pointed out by Shin Hong, IPVS doesn't always use atomic operations
> > in an atomic manner. While this seems unlikely to be manifest in
> > strange behaviour, it seems appropriate to clean this up.
> > 
> > Cc: 홍신 shin hong <hongshin@gmail.com>
> > Signed-off-by: Simon Horman <horms@verge.net.au>
> 
> Applied, thanks.
> 
> >  	if (af == AF_INET &&
> >  	    (ip_vs_sync_state & IP_VS_STATE_MASTER) &&
> >  	    (((cp->protocol != IPPROTO_TCP ||
> >  	       cp->state == IP_VS_TCP_S_ESTABLISHED) &&
> > -	      (atomic_read(&cp->in_pkts) % sysctl_ip_vs_sync_threshold[1]
> > +	      (pkts % sysctl_ip_vs_sync_threshold[1]
> 
> It seems that proc_do_sync_threshold() should check whether this value
> is zero. The current checks also look racy since incorrect values are
> first updated, then overwritten again.

Thanks, I'll look into that.

^ permalink raw reply

* [PATCH] atm/br2684: netif_stop_queue() when atm device busy and netif_wake_queue() when we can send packets again.
From: Chas Williams (CONTRACTOR) @ 2009-08-31 14:29 UTC (permalink / raw)
  To: davem; +Cc: netdev, Karl Hiramoto
In-Reply-To: <1251545092-18081-1-git-send-email-karl@hiramoto.org>

This patch removes the call to dev_kfree_skb() when the atm device is busy.
Calling dev_kfree_skb() causes heavy packet loss then the device is under
heavy load, the more correct behavior should be to stop the upper layers,
then when the lower device can queue packets again wake the upper layers.

Signed-off-by: Karl Hiramoto <karl@hiramoto.org>
Signed-off-by: Chas Williams <chas@cmf.nrl.navy.mil>
---
 net/atm/br2684.c |   37 +++++++++++++++++++++++++++----------
 1 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index 2912665..5c42225 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -69,7 +69,7 @@ struct br2684_vcc {
 	struct net_device *device;
 	/* keep old push, pop functions for chaining */
 	void (*old_push) (struct atm_vcc * vcc, struct sk_buff * skb);
-	/* void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb); */
+	void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb);
 	enum br2684_encaps encaps;
 	struct list_head brvccs;
 #ifdef CONFIG_ATM_BR2684_IPFILTER
@@ -142,6 +142,22 @@ static struct net_device *br2684_find_dev(const struct br
2684_if_spec *s)
 	return NULL;
 }
 
+/* chained vcc->pop function.  Check if we should wake the netif_queue */
+static void br2684_pop(struct atm_vcc *vcc, struct sk_buff *skb)
+{
+	struct br2684_vcc *brvcc = BR2684_VCC(vcc);
+	struct net_device *net_dev = skb->dev;
+
+	pr_debug("br2684_pop(vcc %p ; net_dev %p )\n", vcc, net_dev);
+	brvcc->old_pop(vcc, skb);
+
+	if (!net_dev)
+		return;
+
+	if (atm_may_send(vcc, 0))
+		netif_wake_queue(net_dev);
+
+}
 /*
  * Send a packet out a particular vcc.  Not to useful right now, but paves
  * the way for multiple vcc's per itf.  Returns true if we can send,
@@ -200,20 +216,19 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct n
et_device *dev,
 
 	ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc;
 	pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev);
-	if (!atm_may_send(atmvcc, skb->truesize)) {
-		/*
-		 * We free this here for now, because we cannot know in a highe
r
-		 * layer whether the skb pointer it supplied wasn't freed yet.
-		 * Now, it always is.
-		 */
-		dev_kfree_skb(skb);
-		return 0;
-	}
 	atomic_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc);
 	ATM_SKB(skb)->atm_options = atmvcc->atm_options;
 	dev->stats.tx_packets++;
 	dev->stats.tx_bytes += skb->len;
 	atmvcc->send(atmvcc, skb);
+
+	if (!atm_may_send(atmvcc, 0)) {
+		netif_stop_queue(brvcc->device);
+		/*check for race with br2684_pop*/
+		if (atm_may_send(atmvcc, 0))
+			netif_start_queue(brvcc->device);
+	}
+
 	return 1;
 }
 
@@ -503,8 +518,10 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __u
ser * arg)
 	atmvcc->user_back = brvcc;
 	brvcc->encaps = (enum br2684_encaps)be.encaps;
 	brvcc->old_push = atmvcc->push;
+	brvcc->old_pop = atmvcc->pop;
 	barrier();
 	atmvcc->push = br2684_push;
+	atmvcc->pop = br2684_pop;
 
 	__skb_queue_head_init(&queue);
 	rq = &sk_atm(atmvcc)->sk_receive_queue;

^ permalink raw reply related

* Re: [patch, v2] IPVS: Add handling of incoming ICMPV6 messages
From: Patrick McHardy @ 2009-08-31 14:23 UTC (permalink / raw)
  To: Simon Horman; +Cc: lvs-devel, netdev, David Miller, Julius Volz, Rob Gallagher
In-Reply-To: <20090831075904.GA3430@verge.net.au>

Simon Horman wrote:
> From: Julius Volz <julius.volz@gmail.com>
> 
> IPVS: Add handling of incoming ICMPV6 messages
> 
> Add handling of incoming ICMPv6 messages.
> This follows the handling of IPv4 ICMP messages.
> 
> Amongst ther things this problem allows IPVS to behave sensibly
> when an ICMPV6_PKT_TOOBIG message is received:
> 
>     This message is received when a realserver sends a packet >PMTU to the
>     client. The hop on this path with insufficient MTU will generate an
>     ICMPv6 Packet Too Big message back to the VIP. The LVS server receives
>     this message, but the call to the function handling this has been
>     missing. Thus, IPVS fails to forward the message to the real server,
>     which then does not adjust the path MTU. This patch adds the missing
>     call to ip_vs_in_icmp_v6() in ip_vs_in() to handle this situation.
> 
>     Thanks to Rob Gallagher from HEAnet for reporting this issue and for
>     testing this patch in production (with direct routing mode).

Applied, thanks.

^ permalink raw reply

* Re: [PATCH 3/3] Revert Backoff [v3]: Calculate TCP's connection close threshold as a time value.
From: Eric Dumazet @ 2009-08-31 14:04 UTC (permalink / raw)
  Cc: Damian Lukowski, Netdev
In-Reply-To: <4A9BD7AB.7060207@gmail.com>

Eric Dumazet a écrit :
> Damian Lukowski a écrit :
>> RFC 1122 specifies two threshold values R1 and R2 for connection timeouts,
>> which may represent a number of allowed retransmissions or a timeout value.
>> Currently linux uses sysctl_tcp_retries{1,2} to specify the thresholds
>> in number of allowed retransmissions.
>>
>> For any desired threshold R2 (by means of time) one can specify tcp_retries2
>> (by means of number of retransmissions) such that TCP will not time out
>> earlier than R2. This is the case, because the RTO schedule follows a fixed
>> pattern, namely exponential backoff.
>>
>> However, the RTO behaviour is not predictable any more if RTO backoffs can be
>> reverted, as it is the case in the draft
>> "Make TCP more Robust to Long Connectivity Disruptions"
>> (http://tools.ietf.org/html/draft-zimmermann-tcp-lcd).
>>
>> In the worst case TCP would time out a connection after 3.2 seconds, if the
>> initial RTO equaled MIN_RTO and each backoff has been reverted.
>>
>> This patch introduces a function retransmits_timed_out(N),
>> which calculates the timeout of a TCP connection, assuming an initial
>> RTO of MIN_RTO and N unsuccessful, exponentially backed-off retransmissions.
>>
>> Whenever timeout decisions are made by comparing the retransmission counter
>> to some value N, this function can be used, instead.
>>
>> The meaning of tcp_retries2 will be changed, as many more RTO retransmissions
>> can occur than the value indicates. However, it yields a timeout which is
>> similar to the one of an unpatched, exponentially backing off TCP in the same
>> scenario. As no application could rely on an RTO greater than MIN_RTO, there
>> should be no risk of a regression.
>>
>> Signed-off-by: Damian Lukowski <damian@tvk.rwth-aachen.de>
>> ---
>>  include/net/tcp.h    |   18 ++++++++++++++++++
>>  net/ipv4/tcp_timer.c |   11 +++++++----
>>  2 files changed, 25 insertions(+), 4 deletions(-)
>>
>> diff --git a/include/net/tcp.h b/include/net/tcp.h
>> index c35b329..17d1a88 100644
>> --- a/include/net/tcp.h
>> +++ b/include/net/tcp.h
>> @@ -1247,6 +1247,24 @@ static inline struct sk_buff *tcp_write_queue_prev(struct sock *sk, struct sk_bu
>>  #define tcp_for_write_queue_from_safe(skb, tmp, sk)			\
>>  	skb_queue_walk_from_safe(&(sk)->sk_write_queue, skb, tmp)
>>  
>> +static inline bool retransmits_timed_out(const struct sock *sk,
>> +					 unsigned int boundary)
>> +{
>> +	int limit, K;
>> +	if (!inet_csk(sk)->icsk_retransmits)
>> +		return false;
>> +
>> +	K = ilog2(TCP_RTO_MAX/TCP_RTO_MIN);
>> +
>> +	if (boundary <= K)
>> +		limit = ((2 << boundary) - 1) * TCP_RTO_MIN;
>> +	else
>> +		limit = ((2 << K) - 1) * TCP_RTO_MIN +
>> +			(boundary - K) * TCP_RTO_MAX;
> 
> Doing this computation might allow us to respect RFC 1122 here :
>  
> "The value of R2 SHOULD correspond to at least 100 seconds."
> 
> adding a third parameter to retransmits_timed_out(), min_limit,
> being 100*HZ if sysctl_tcp_retries2 was used...
> 
> limit = min(min_limit, limit);
> 

Oh well, typical min/max error, sorry :)

> 
>> +
>> +	return (tcp_time_stamp - tcp_sk(sk)->retrans_stamp) >= limit;
>> +}
>> +
>>  static inline struct sk_buff *tcp_send_head(struct sock *sk)
>>  {
>>  	return sk->sk_send_head;
>> diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
>> index a3ba494..2972d7b 100644
>> --- a/net/ipv4/tcp_timer.c
>> +++ b/net/ipv4/tcp_timer.c
>> @@ -137,13 +137,14 @@ static int tcp_write_timeout(struct sock *sk)
>>  {
>>  	struct inet_connection_sock *icsk = inet_csk(sk);
>>  	int retry_until;
>> +	bool do_reset;
>>  
>>  	if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
>>  		if (icsk->icsk_retransmits)
>>  			dst_negative_advice(&sk->sk_dst_cache);
>>  		retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries;
>>  	} else {
>> -		if (icsk->icsk_retransmits >= sysctl_tcp_retries1) {
>> +		if (retransmits_timed_out(sk, sysctl_tcp_retries1)) {
>>  			/* Black hole detection */
>>  			tcp_mtu_probing(icsk, sk);
>>  
>> @@ -155,13 +156,15 @@ static int tcp_write_timeout(struct sock *sk)
>>  			const int alive = (icsk->icsk_rto < TCP_RTO_MAX);
>>  
>>  			retry_until = tcp_orphan_retries(sk, alive);
>> +			do_reset = alive ||
>> +				   !retransmits_timed_out(sk, retry_until);
>>  
>> -			if (tcp_out_of_resources(sk, alive || icsk->icsk_retransmits < retry_until))
>> +			if (tcp_out_of_resources(sk, do_reset))
>>  				return 1;
>>  		}
>>  	}
>>  
>> -	if (icsk->icsk_retransmits >= retry_until) {
>> +	if (retransmits_timed_out(sk, retry_until)) {
>>  		/* Has it gone just too far? */
>>  		tcp_write_err(sk);
>>  		return 1;
>> @@ -385,7 +388,7 @@ void tcp_retransmit_timer(struct sock *sk)
>>  out_reset_timer:
>>  	icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
>>  	inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX);
>> -	if (icsk->icsk_retransmits > sysctl_tcp_retries1)
>> +	if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1))
>>  		__sk_dst_reset(sk);
>>  
>>  out:;
> 
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 


^ permalink raw reply

* Re: [PATCH 3/3] Revert Backoff [v3]: Calculate TCP's connection close threshold as a time value.
From: Eric Dumazet @ 2009-08-31 14:01 UTC (permalink / raw)
  To: Damian Lukowski; +Cc: Netdev
In-Reply-To: <4A950B82.1070807@tvk.rwth-aachen.de>

Damian Lukowski a écrit :
> RFC 1122 specifies two threshold values R1 and R2 for connection timeouts,
> which may represent a number of allowed retransmissions or a timeout value.
> Currently linux uses sysctl_tcp_retries{1,2} to specify the thresholds
> in number of allowed retransmissions.
> 
> For any desired threshold R2 (by means of time) one can specify tcp_retries2
> (by means of number of retransmissions) such that TCP will not time out
> earlier than R2. This is the case, because the RTO schedule follows a fixed
> pattern, namely exponential backoff.
> 
> However, the RTO behaviour is not predictable any more if RTO backoffs can be
> reverted, as it is the case in the draft
> "Make TCP more Robust to Long Connectivity Disruptions"
> (http://tools.ietf.org/html/draft-zimmermann-tcp-lcd).
> 
> In the worst case TCP would time out a connection after 3.2 seconds, if the
> initial RTO equaled MIN_RTO and each backoff has been reverted.
> 
> This patch introduces a function retransmits_timed_out(N),
> which calculates the timeout of a TCP connection, assuming an initial
> RTO of MIN_RTO and N unsuccessful, exponentially backed-off retransmissions.
> 
> Whenever timeout decisions are made by comparing the retransmission counter
> to some value N, this function can be used, instead.
> 
> The meaning of tcp_retries2 will be changed, as many more RTO retransmissions
> can occur than the value indicates. However, it yields a timeout which is
> similar to the one of an unpatched, exponentially backing off TCP in the same
> scenario. As no application could rely on an RTO greater than MIN_RTO, there
> should be no risk of a regression.
> 
> Signed-off-by: Damian Lukowski <damian@tvk.rwth-aachen.de>
> ---
>  include/net/tcp.h    |   18 ++++++++++++++++++
>  net/ipv4/tcp_timer.c |   11 +++++++----
>  2 files changed, 25 insertions(+), 4 deletions(-)
> 
> diff --git a/include/net/tcp.h b/include/net/tcp.h
> index c35b329..17d1a88 100644
> --- a/include/net/tcp.h
> +++ b/include/net/tcp.h
> @@ -1247,6 +1247,24 @@ static inline struct sk_buff *tcp_write_queue_prev(struct sock *sk, struct sk_bu
>  #define tcp_for_write_queue_from_safe(skb, tmp, sk)			\
>  	skb_queue_walk_from_safe(&(sk)->sk_write_queue, skb, tmp)
>  
> +static inline bool retransmits_timed_out(const struct sock *sk,
> +					 unsigned int boundary)
> +{
> +	int limit, K;
> +	if (!inet_csk(sk)->icsk_retransmits)
> +		return false;
> +
> +	K = ilog2(TCP_RTO_MAX/TCP_RTO_MIN);
> +
> +	if (boundary <= K)
> +		limit = ((2 << boundary) - 1) * TCP_RTO_MIN;
> +	else
> +		limit = ((2 << K) - 1) * TCP_RTO_MIN +
> +			(boundary - K) * TCP_RTO_MAX;

Doing this computation might allow us to respect RFC 1122 here :
 
"The value of R2 SHOULD correspond to at least 100 seconds."

adding a third parameter to retransmits_timed_out(), min_limit,
being 100*HZ if sysctl_tcp_retries2 was used...

limit = min(min_limit, limit);


> +
> +	return (tcp_time_stamp - tcp_sk(sk)->retrans_stamp) >= limit;
> +}
> +
>  static inline struct sk_buff *tcp_send_head(struct sock *sk)
>  {
>  	return sk->sk_send_head;
> diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
> index a3ba494..2972d7b 100644
> --- a/net/ipv4/tcp_timer.c
> +++ b/net/ipv4/tcp_timer.c
> @@ -137,13 +137,14 @@ static int tcp_write_timeout(struct sock *sk)
>  {
>  	struct inet_connection_sock *icsk = inet_csk(sk);
>  	int retry_until;
> +	bool do_reset;
>  
>  	if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
>  		if (icsk->icsk_retransmits)
>  			dst_negative_advice(&sk->sk_dst_cache);
>  		retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries;
>  	} else {
> -		if (icsk->icsk_retransmits >= sysctl_tcp_retries1) {
> +		if (retransmits_timed_out(sk, sysctl_tcp_retries1)) {
>  			/* Black hole detection */
>  			tcp_mtu_probing(icsk, sk);
>  
> @@ -155,13 +156,15 @@ static int tcp_write_timeout(struct sock *sk)
>  			const int alive = (icsk->icsk_rto < TCP_RTO_MAX);
>  
>  			retry_until = tcp_orphan_retries(sk, alive);
> +			do_reset = alive ||
> +				   !retransmits_timed_out(sk, retry_until);
>  
> -			if (tcp_out_of_resources(sk, alive || icsk->icsk_retransmits < retry_until))
> +			if (tcp_out_of_resources(sk, do_reset))
>  				return 1;
>  		}
>  	}
>  
> -	if (icsk->icsk_retransmits >= retry_until) {
> +	if (retransmits_timed_out(sk, retry_until)) {
>  		/* Has it gone just too far? */
>  		tcp_write_err(sk);
>  		return 1;
> @@ -385,7 +388,7 @@ void tcp_retransmit_timer(struct sock *sk)
>  out_reset_timer:
>  	icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
>  	inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX);
> -	if (icsk->icsk_retransmits > sysctl_tcp_retries1)
> +	if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1))
>  		__sk_dst_reset(sk);
>  
>  out:;


^ permalink raw reply

* Re: [PATCH 1/3] Revert Backoff [v3]: Rename skb to icmp_skb in tcp_v4_err()
From: David Miller @ 2009-08-31 13:34 UTC (permalink / raw)
  To: ilpo.jarvinen; +Cc: damian, netdev
In-Reply-To: <alpine.DEB.2.00.0908311538050.29341@wel-95.cs.helsinki.fi>

From: "Ilpo Järvinen" <ilpo.jarvinen@helsinki.fi>
Date: Mon, 31 Aug 2009 16:22:58 +0300 (EEST)

> Not that related to the purpose of this patch but still worth to
> mention now that we are in the context... ...I wonder if this should
> be pskb_may_pull instead of direct compare here regardless of this
> change?

ICMP layer that invokes this code makes sure enough headers
are in the linear area already.

> Acked-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>

Thanks for reviewing.

^ permalink raw reply

* Re: [PATCH resend] drop_monitor: fix trace_napi_poll_hit()
From: Eric Dumazet @ 2009-08-31 13:33 UTC (permalink / raw)
  To: Neil Horman; +Cc: Xiao Guangrong, David Miller, Wei Yongjun, Netdev, LKML
In-Reply-To: <20090831111245.GA2105@hmsreliant.think-freely.org>

Neil Horman a écrit :
> I still see a large number of drivers that update dev->last_rx, although its
> not all as I look through the list, so something definately seems amiss.

Some drivers still update dev->last_rx for their own needs, not a core
network concern.

But a cleanup is certainly possible on few other drivers, about a dozen
if I count correctly.

> 
> If its not going to be consistently updated, why are still carrying that field
> in dev?  Are we just waiting on someone to do the janitorial work to remove it?
> If so, I can, and I'll fix up the drop monitor in the process, to use a private
> timestamp.

We have to keep dev->last_rx for bonding use, so please use a private
timestamp for drop monitor.

Thanks

^ permalink raw reply

* Re: [PATCH] ip6tables: Read outside array bounds
From: Patrick McHardy @ 2009-08-31 13:31 UTC (permalink / raw)
  To: Roel Kluin; +Cc: David S. Miller, netdev, Andrew Morton
In-Reply-To: <4A966C94.1060703@gmail.com>

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

Roel Kluin wrote:
> Check bounds before reading from the s6_addr array. It read 1 past
> the end at s6_addr[16] and eui64[] was also read 1 past the end.
> 
> diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c
> index db610ba..7b40a20 100644
> --- a/net/ipv6/netfilter/ip6t_eui64.c
> +++ b/net/ipv6/netfilter/ip6t_eui64.c
> @@ -43,8 +43,8 @@ eui64_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
>  			eui64[0] ^= 0x02;
>  
>  			i = 0;
> -			while (ipv6_hdr(skb)->saddr.s6_addr[8 + i] == eui64[i]
> -			       && i < 8)
> +			while (i < 8 && ipv6_hdr(skb)->saddr.s6_addr[8 + i] ==
> +					eui64[i])
>  				i++;
>  
>  			if (i == 8)

Nice catch, thanks. We might as well use memcmp though, so I've
committed this patch:


[-- Attachment #2: x --]
[-- Type: text/plain, Size: 1203 bytes --]

commit 488908696971c5ea1dcc5d13f29c158ba4f6ae7d
Author: Patrick McHardy <kaber@trash.net>
Date:   Mon Aug 31 15:30:31 2009 +0200

    netfilter: ip6t_eui: fix read outside array bounds
    
    Use memcmp() instead of open coded comparison that reads one byte past
    the intended end.
    
    Based on patch from Roel Kluin <roel.kluin@gmail.com>
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>

diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c
index db610ba..ca287f6 100644
--- a/net/ipv6/netfilter/ip6t_eui64.c
+++ b/net/ipv6/netfilter/ip6t_eui64.c
@@ -23,7 +23,6 @@ static bool
 eui64_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
 {
 	unsigned char eui64[8];
-	int i = 0;
 
 	if (!(skb_mac_header(skb) >= skb->head &&
 	      skb_mac_header(skb) + ETH_HLEN <= skb->data) &&
@@ -42,12 +41,8 @@ eui64_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
 			eui64[4] = 0xfe;
 			eui64[0] ^= 0x02;
 
-			i = 0;
-			while (ipv6_hdr(skb)->saddr.s6_addr[8 + i] == eui64[i]
-			       && i < 8)
-				i++;
-
-			if (i == 8)
+			if (!memcmp(ipv6_hdr(skb)->saddr.s6_addr + 8, eui64,
+				    sizeof(eui64)))
 				return true;
 		}
 	}

^ permalink raw reply related

* Re: [PATCH 3/3] Revert Backoff [v3]: Calculate TCP's connection close threshold as a time value.
From: Ilpo Järvinen @ 2009-08-31 13:26 UTC (permalink / raw)
  To: Damian Lukowski; +Cc: Netdev, David Miller
In-Reply-To: <4A950B82.1070807@tvk.rwth-aachen.de>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 5801 bytes --]

On Wed, 26 Aug 2009, Damian Lukowski wrote:

> RFC 1122 specifies two threshold values R1 and R2 for connection timeouts,
> which may represent a number of allowed retransmissions or a timeout value.
> Currently linux uses sysctl_tcp_retries{1,2} to specify the thresholds
> in number of allowed retransmissions.
>
> For any desired threshold R2 (by means of time) one can specify tcp_retries2
> (by means of number of retransmissions) such that TCP will not time out
> earlier than R2. This is the case, because the RTO schedule follows a fixed
> pattern, namely exponential backoff.
>
> However, the RTO behaviour is not predictable any more if RTO backoffs can be
> reverted, as it is the case in the draft
> "Make TCP more Robust to Long Connectivity Disruptions"
> (http://tools.ietf.org/html/draft-zimmermann-tcp-lcd).
>
> In the worst case TCP would time out a connection after 3.2 seconds, if the
> initial RTO equaled MIN_RTO and each backoff has been reverted.
>
> This patch introduces a function retransmits_timed_out(N),
> which calculates the timeout of a TCP connection, assuming an initial
> RTO of MIN_RTO and N unsuccessful, exponentially backed-off retransmissions.
>
> Whenever timeout decisions are made by comparing the retransmission counter
> to some value N, this function can be used, instead.
>
> The meaning of tcp_retries2 will be changed, as many more RTO retransmissions
> can occur than the value indicates. However, it yields a timeout which is
> similar to the one of an unpatched, exponentially backing off TCP in the same
> scenario. As no application could rely on an RTO greater than MIN_RTO, there
> should be no risk of a regression.
>
> Signed-off-by: Damian Lukowski <damian@tvk.rwth-aachen.de>
> ---
> include/net/tcp.h    |   18 ++++++++++++++++++
> net/ipv4/tcp_timer.c |   11 +++++++----
> 2 files changed, 25 insertions(+), 4 deletions(-)
>
> diff --git a/include/net/tcp.h b/include/net/tcp.h
> index c35b329..17d1a88 100644
> --- a/include/net/tcp.h
> +++ b/include/net/tcp.h
> @@ -1247,6 +1247,24 @@ static inline struct sk_buff *tcp_write_queue_prev(struct sock *sk, struct sk_bu
> #define tcp_for_write_queue_from_safe(skb, tmp, sk)			\
> 	skb_queue_walk_from_safe(&(sk)->sk_write_queue, skb, tmp)
>

IMHO, having an introductionary comment here wouldn't hurt as this is a 
bit tricky thing we end up doing here :-).

> +static inline bool retransmits_timed_out(const struct sock *sk,
> +					 unsigned int boundary)
> +{
> +	int limit, K;

An empty line after local variables. Just rename the K to max_backoff or 
something like that (more meaningful).

> +	if (!inet_csk(sk)->icsk_retransmits)
> +		return false;
> +
> +	K = ilog2(TCP_RTO_MAX/TCP_RTO_MIN);
> +
> +	if (boundary <= K)
> +		limit = ((2 << boundary) - 1) * TCP_RTO_MIN;
> +	else
> +		limit = ((2 << K) - 1) * TCP_RTO_MIN +
> +			(boundary - K) * TCP_RTO_MAX;
> +
> +	return (tcp_time_stamp - tcp_sk(sk)->retrans_stamp) >= limit;
> +}
> +
> static inline struct sk_buff *tcp_send_head(struct sock *sk)
> {
> 	return sk->sk_send_head;
> diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
> index a3ba494..2972d7b 100644
> --- a/net/ipv4/tcp_timer.c
> +++ b/net/ipv4/tcp_timer.c
> @@ -137,13 +137,14 @@ static int tcp_write_timeout(struct sock *sk)
> {
> 	struct inet_connection_sock *icsk = inet_csk(sk);
> 	int retry_until;
> +	bool do_reset;
>
> 	if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
> 		if (icsk->icsk_retransmits)
> 			dst_negative_advice(&sk->sk_dst_cache);
> 		retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries;
> 	} else {
> -		if (icsk->icsk_retransmits >= sysctl_tcp_retries1) {
> +		if (retransmits_timed_out(sk, sysctl_tcp_retries1)) {
> 			/* Black hole detection */
> 			tcp_mtu_probing(icsk, sk);
>
> @@ -155,13 +156,15 @@ static int tcp_write_timeout(struct sock *sk)
> 			const int alive = (icsk->icsk_rto < TCP_RTO_MAX);
>
> 			retry_until = tcp_orphan_retries(sk, alive);
> +			do_reset = alive ||
> +				   !retransmits_timed_out(sk, retry_until);
>
> -			if (tcp_out_of_resources(sk, alive || icsk->icsk_retransmits < retry_until))
> +			if (tcp_out_of_resources(sk, do_reset))
> 				return 1;
> 		}
> 	}
>
> -	if (icsk->icsk_retransmits >= retry_until) {
> +	if (retransmits_timed_out(sk, retry_until)) {
> 		/* Has it gone just too far? */
> 		tcp_write_err(sk);
> 		return 1;
> @@ -385,7 +388,7 @@ void tcp_retransmit_timer(struct sock *sk)
> out_reset_timer:
> 	icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
> 	inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX);
> -	if (icsk->icsk_retransmits > sysctl_tcp_retries1)
> +	if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1))
> 		__sk_dst_reset(sk);
>
> out:;

The implementation itself seems ok. I was a bit concerned that the use of 
retrans_stamp would result in considerably different behavior than the use 
of icsk_retransmits but it seems I was wrong.

Acked-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>

I'm fine with this approach as no matter what we would do the previous 
approach just isn't fitting the new model that breaks the assumptions 
behind the previous model. I don't expect the change in the timing to be 
significant for anybody unless one did copy our code exactly somewhere 
(including rtt calculation). ...but if somebody has some objections in 
this, please speak up! After all, it will change how the sysctl behaves.

Perhaps we should mention this artificial timing change in 
ip-sysctl.txt too...?

It would be worth to do a trivial pull-the-plug testing comparing this and 
the previous approach in the rto < TCP_RTO_MIN region without any icmps to 
verify that this didn't change the timing a bit, afaict, it shouldn't (If 
you didn't do that already). Just to be on very sure grounds.


-- 
  i.

^ permalink raw reply

* Re: [PATCH 2/3] Revert Backoff [v3]: Revert RTO on ICMP destination unreachable
From: Ilpo Järvinen @ 2009-08-31 13:23 UTC (permalink / raw)
  To: Damian Lukowski; +Cc: Netdev, David Miller
In-Reply-To: <4A950B7F.6000702@tvk.rwth-aachen.de>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 6055 bytes --]

On Wed, 26 Aug 2009, Damian Lukowski wrote:

> Here, an ICMP host/network unreachable message, whose payload fits to
> TCP's SND.UNA, is taken as an indication that the RTO retransmission has
> not been lost due to congestion, but because of a route failure
> somewhere along the path.
> With true congestion, a router won't trigger such a message and the
> patched TCP will operate as standard TCP.
>
> This patch reverts one RTO backoff, if an ICMP host/network unreachable
> message, whose payload fits to TCP's SND.UNA, arrives.
> Based on the new RTO, the retransmission timer is reset to reflect the
> remaining time, or - if the revert clocked out the timer - a retransmission
> is sent out immediately.
> Backoffs are only reverted, if TCP is in RTO loss recovery, i.e. if
> there have been retransmissions and reversible backoffs, already.
>
> Changes from v2:
> 1) Renaming of skb in tcp_v4_err() moved to another patch.
> 2) Reintroduced tcp_bound_rto() and __tcp_set_rto().
> 3) Fixed code comments.
>
> Signed-off-by: Damian Lukowski <damian@tvk.rwth-aachen.de>
> ---
> include/net/tcp.h    |   12 ++++++++++++
> net/ipv4/tcp_input.c |    5 ++---
> net/ipv4/tcp_ipv4.c  |   37 +++++++++++++++++++++++++++++++++++++
> net/ipv4/tcp_timer.c |    2 +-
> 4 files changed, 52 insertions(+), 4 deletions(-)
>
> diff --git a/include/net/tcp.h b/include/net/tcp.h
> index 88af843..c35b329 100644
> --- a/include/net/tcp.h
> +++ b/include/net/tcp.h
> @@ -469,6 +469,7 @@ extern void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss,
> 				      int nonagle);
> extern int tcp_may_send_now(struct sock *sk);
> extern int tcp_retransmit_skb(struct sock *, struct sk_buff *);
> +extern void tcp_retransmit_timer(struct sock *sk);
> extern void tcp_xmit_retransmit_queue(struct sock *);
> extern void tcp_simple_retransmit(struct sock *);
> extern int tcp_trim_head(struct sock *, struct sk_buff *, u32);
> @@ -521,6 +522,17 @@ extern int tcp_mtu_to_mss(struct sock *sk, int pmtu);
> extern int tcp_mss_to_mtu(struct sock *sk, int mss);
> extern void tcp_mtup_init(struct sock *sk);
>
> +static inline void tcp_bound_rto(const struct sock *sk)
> +{
> +	if (inet_csk(sk)->icsk_rto > TCP_RTO_MAX)
> +		inet_csk(sk)->icsk_rto = TCP_RTO_MAX;
> +}
> +
> +static inline u32 __tcp_set_rto(const struct tcp_sock *tp)
> +{
> +	return (tp->srtt >> 3) + tp->rttvar;
> +}
> +
> static inline void __tcp_fast_path_on(struct tcp_sock *tp, u32 snd_wnd)
> {
> 	tp->pred_flags = htonl((tp->tcp_header_len << 26) |
> diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
> index 2bdb0da..af6d6fa 100644
> --- a/net/ipv4/tcp_input.c
> +++ b/net/ipv4/tcp_input.c
> @@ -685,7 +685,7 @@ static inline void tcp_set_rto(struct sock *sk)
> 	 *    is invisible. Actually, Linux-2.4 also generates erratic
> 	 *    ACKs in some circumstances.
> 	 */
> -	inet_csk(sk)->icsk_rto = (tp->srtt >> 3) + tp->rttvar;
> +	inet_csk(sk)->icsk_rto = __tcp_set_rto(tp);
>
> 	/* 2. Fixups made earlier cannot be right.
> 	 *    If we do not estimate RTO correctly without them,
> @@ -696,8 +696,7 @@ static inline void tcp_set_rto(struct sock *sk)
> 	/* NOTE: clamping at TCP_RTO_MIN is not required, current algo
> 	 * guarantees that rto is higher.
> 	 */
> -	if (inet_csk(sk)->icsk_rto > TCP_RTO_MAX)
> -		inet_csk(sk)->icsk_rto = TCP_RTO_MAX;
> +	tcp_bound_rto(sk);
> }
>
> /* Save metrics learned by this TCP session.
> diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
> index 6ca1bc8..6755e29 100644
> --- a/net/ipv4/tcp_ipv4.c
> +++ b/net/ipv4/tcp_ipv4.c
> @@ -332,12 +332,15 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
> {
> 	struct iphdr *iph = (struct iphdr *)icmp_skb->data;
> 	struct tcphdr *th = (struct tcphdr *)(icmp_skb->data + (iph->ihl << 2));
> +	struct inet_connection_sock *icsk;
> 	struct tcp_sock *tp;
> 	struct inet_sock *inet;
> 	const int type = icmp_hdr(icmp_skb)->type;
> 	const int code = icmp_hdr(icmp_skb)->code;
> 	struct sock *sk;
> +	struct sk_buff *skb;
> 	__u32 seq;
> +	__u32 remaining;
> 	int err;
> 	struct net *net = dev_net(icmp_skb->dev);
>
> @@ -367,6 +370,7 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
> 	if (sk->sk_state == TCP_CLOSE)
> 		goto out;
>
> +	icsk = inet_csk(sk);
> 	tp = tcp_sk(sk);
> 	seq = ntohl(th->seq);
> 	if (sk->sk_state != TCP_LISTEN &&
> @@ -393,6 +397,39 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
> 		}
>
> 		err = icmp_err_convert[code].errno;
> +		/* check if icmp_skb allows revert of backoff
> +		 * (see draft-zimmermann-tcp-lcd) */
> +		if (code != ICMP_NET_UNREACH && code != ICMP_HOST_UNREACH)
> +			break;
> +		if (seq != tp->snd_una  || !icsk->icsk_retransmits ||
> +		    !icsk->icsk_backoff)
> +			break;
> +
> +		icsk->icsk_backoff--;
> +		inet_csk(sk)->icsk_rto = __tcp_set_rto(tp) <<
> +					 icsk->icsk_backoff;
> +		tcp_bound_rto(sk);
> +
> +		skb = tcp_write_queue_head(sk);
> +		BUG_ON(!skb);
> +
> +		remaining = icsk->icsk_rto - min(icsk->icsk_rto,
> +				tcp_time_stamp - TCP_SKB_CB(skb)->when);
> +
> +		if (remaining) {
> +			inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
> +						  remaining, TCP_RTO_MAX);
> +		} else if (sock_owned_by_user(sk)) {
> +			/* RTO revert clocked out retransmission,
> +			 * but socket is locked. Will defer. */
> +			inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
> +						  HZ/20, TCP_RTO_MAX);
> +		} else {
> +			/* RTO revert clocked out retransmission.
> +			 * Will retransmit now */
> +			tcp_retransmit_timer(sk);
> +		}
> +
> 		break;
> 	case ICMP_TIME_EXCEEDED:
> 		err = EHOSTUNREACH;
> diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
> index b144a26..a3ba494 100644
> --- a/net/ipv4/tcp_timer.c
> +++ b/net/ipv4/tcp_timer.c
> @@ -279,7 +279,7 @@ static void tcp_probe_timer(struct sock *sk)
>  *	The TCP retransmit timer.
>  */
>
> -static void tcp_retransmit_timer(struct sock *sk)
> +void tcp_retransmit_timer(struct sock *sk)
> {
> 	struct tcp_sock *tp = tcp_sk(sk);
> 	struct inet_connection_sock *icsk = inet_csk(sk);
>

Acked-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>

-- 
  i.

^ permalink raw reply

* Re: [PATCH 1/3] Revert Backoff [v3]: Rename skb to icmp_skb in tcp_v4_err()
From: Ilpo Järvinen @ 2009-08-31 13:22 UTC (permalink / raw)
  To: Damian Lukowski; +Cc: Netdev, David Miller
In-Reply-To: <4A950B7B.4010601@tvk.rwth-aachen.de>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 2036 bytes --]

On Wed, 26 Aug 2009, Damian Lukowski wrote:

> This supplementary patch renames skb to icmp_skb in tcp_v4_err() in order to
> disambiguate from another sk_buff variable, which will be introduced
> in a separate patch.
>
> Signed-off-by: Damian Lukowski <damian@tvk.rwth-aachen.de>
> ---
> net/ipv4/tcp_ipv4.c |   16 ++++++++--------
> 1 files changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
> index 6d88219..6ca1bc8 100644
> --- a/net/ipv4/tcp_ipv4.c
> +++ b/net/ipv4/tcp_ipv4.c
> @@ -328,26 +328,26 @@ static void do_pmtu_discovery(struct sock *sk, struct iphdr *iph, u32 mtu)
>  *
>  */
>
> -void tcp_v4_err(struct sk_buff *skb, u32 info)
> +void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
> {
> -	struct iphdr *iph = (struct iphdr *)skb->data;
> -	struct tcphdr *th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
> +	struct iphdr *iph = (struct iphdr *)icmp_skb->data;
> +	struct tcphdr *th = (struct tcphdr *)(icmp_skb->data + (iph->ihl << 2));
> 	struct tcp_sock *tp;
> 	struct inet_sock *inet;
> -	const int type = icmp_hdr(skb)->type;
> -	const int code = icmp_hdr(skb)->code;
> +	const int type = icmp_hdr(icmp_skb)->type;
> +	const int code = icmp_hdr(icmp_skb)->code;
> 	struct sock *sk;
> 	__u32 seq;
> 	int err;
> -	struct net *net = dev_net(skb->dev);
> +	struct net *net = dev_net(icmp_skb->dev);
>
> -	if (skb->len < (iph->ihl << 2) + 8) {
> +	if (icmp_skb->len < (iph->ihl << 2) + 8) {

Not that related to the purpose of this patch but still worth to 
mention now that we are in the context... ...I wonder if this should be 
pskb_may_pull instead of direct compare here regardless of this change?

> 		ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);
> 		return;
> 	}
>
> 	sk = inet_lookup(net, &tcp_hashinfo, iph->daddr, th->dest,
> -			iph->saddr, th->source, inet_iif(skb));
> +			iph->saddr, th->source, inet_iif(icmp_skb));
> 	if (!sk) {
> 		ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);
> 		return;
>

Acked-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>

-- 
  i.

^ permalink raw reply

* Re: Latest PreemptRT patch error on imx35
From: Uwe Kleine-König @ 2009-08-31 13:22 UTC (permalink / raw)
  To: Tim Sander
  Cc: linux-rt-users, David S. Miller, Sascha Hauer, Greg Ungerer,
	netdev
In-Reply-To: <200908311143.08952.tim01@vlsi.informatik.tu-darmstadt.de>

Hello Tim,

> I just bootet 2.6.31-rc8-rt9 on the phycore-imx35 development board, 
> without any additional patches. The FEC Ethernet Controller went belly 
> up, but the system booted nevertheless. [...]
The problem is that &fep->mii_lock is taken twice.  On a normal (i.e.
non-RT) UP system that doesn't hurt because spinlocks are noops (unless
you have some debugging code activated).

The exact problem is:
	fec_enet_mii (this takes &fep->mii_lock) and calls mip->mii_func
	which happens to be mii_queue.  mii_queue in turn takes
	&fep->mii_lock again.

The correct fix is probably to split mii_queue into a function that
locks and a function that does the actual work.  And then use the latter
in fec_enet_mii.

I'd prepare a patch but my wife just called me to eat some cake :-)

So maybe later today or tomorrow, we'll see.

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-König            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |
--
To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Network device autoconfiguration
From: Rémi Denis-Courmont @ 2009-08-31 13:19 UTC (permalink / raw)
  To: netdev


   Hello,

The kernel will automatically configure the loopback device, especially,
add 127.0.0.1 and ::1 address. This is detected with the IFF_LOOPBACK flag.
In *some* cases, it would be statically determine the Phonet address of a
device, but I wonder how to pass the information from the net_device driver
to the stack... Would a device ioctl() be appropriate? Or is the whole
thing just a bad idea? Or something else?

-- 
Rémi Denis-Courmont


^ permalink raw reply

* Re: [PATCH] [V3] net: add Xilinx emac lite device driver
From: Michal Simek @ 2009-08-31 13:18 UTC (permalink / raw)
  To: David Miller
  Cc: john.linn, netdev, linuxppc-dev, jgarzik, grant.likely, jwboyer,
	john.williams, sadanan
In-Reply-To: <20090820.025226.26907868.davem@davemloft.net>

Hi David,

I see that John's patch has wrong file permission
-rwxr-xr-x 	xilinx_emaclite.c
<http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git;a=blob;f=drivers/net/xilinx_emaclite.c;h=7e05b40ae36b50b6eb66d9512ae3a49ba2d36a47;hb=a9a8cb1d6594037fbb23f1ce45964ec6a3b38215>
	blob
<http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git;a=blob;f=drivers/net/xilinx_emaclite.c;h=7e05b40ae36b50b6eb66d9512ae3a49ba2d36a47;hb=a9a8cb1d6594037fbb23f1ce45964ec6a3b38215>
| history
<http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git;a=history;f=drivers/net/xilinx_emaclite.c;h=7e05b40ae36b50b6eb66d9512ae3a49ba2d36a47;hb=a9a8cb1d6594037fbb23f1ce45964ec6a3b38215>
| raw
<http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git;a=blob_plain;f=drivers/net/xilinx_emaclite.c;hb=a9a8cb1d6594037fbb23f1ce45964ec6a3b38215>



should be 644.

Please fix it in your repo.

Thanks,
Michal

> From: John Linn <john.linn@xilinx.com>
> Date: Thu, 20 Aug 2009 03:49:51 -0600
>
>   
>> This patch adds support for the Xilinx Ethernet Lite device.  The
>> soft logic core from Xilinx is typically used on Virtex and Spartan
>> designs attached to either a PowerPC or a Microblaze processor.
>>
>> Signed-off-by: Sadanand M <sadanan@xilinx.com>
>> Signed-off-by: John Linn <john.linn@xilinx.com>
>>     
>
> Applied, thanks.
>   


-- 
Michal Simek, Ing. (M.Eng)
PetaLogix - Linux Solutions for a Reconfigurable World
w: www.petalogix.com p: +61-7-30090663,+42-0-721842854 f: +61-7-30090663


^ permalink raw reply

* Re: [PATCH] au1000_eth: possible NULL dereference of aup->mii_bus->irq in au1000_probe()
From: Florian Fainelli @ 2009-08-31 12:38 UTC (permalink / raw)
  To: Roel Kluin; +Cc: netdev, Andrew Morton, David S. Miller
In-Reply-To: <4A9B8C6F.3040503@gmail.com>

Hello Roel,

Le lundi 31 août 2009 10:40:15, Roel Kluin a écrit :
> aup->mii_bus->irq allocation may fail, prevent a dereference of NULL.

Good catch.

>
> Signed-off-by: Roel Kluin <roel.kluin@gmail.com>

Acked-by: Florian Fainelli <florian@openwrt.org>

> ---
> diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
> index d3c734f..02e4be0 100644
> --- a/drivers/net/au1000_eth.c
> +++ b/drivers/net/au1000_eth.c
> @@ -1157,6 +1157,9 @@ static struct net_device * au1000_probe(int port_num)
>  	aup->mii_bus->name = "au1000_eth_mii";
>  	snprintf(aup->mii_bus->id, MII_BUS_ID_SIZE, "%x", aup->mac_id);
>  	aup->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
> +	if (aup->mii_bus->irq == NULL)
> +		goto err_out;
> +
>  	for(i = 0; i < PHY_MAX_ADDR; ++i)
>  		aup->mii_bus->irq[i] = PHY_POLL;
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
Cordialement, Florian Fainelli
------------------------------

^ permalink raw reply

* Re: [patch] ipvs: Use atomic operations atomicly
From: Patrick McHardy @ 2009-08-31 12:22 UTC (permalink / raw)
  To: Simon Horman
  Cc: lvs-devel, netdev, netfilter-devel, 홍신 shin hong,
	David Miller
In-Reply-To: <20090828023722.GA12136@verge.net.au>

Simon Horman wrote:
> A pointed out by Shin Hong, IPVS doesn't always use atomic operations
> in an atomic manner. While this seems unlikely to be manifest in
> strange behaviour, it seems appropriate to clean this up.
> 
> Cc: 홍신 shin hong <hongshin@gmail.com>
> Signed-off-by: Simon Horman <horms@verge.net.au>

Applied, thanks.

>  	if (af == AF_INET &&
>  	    (ip_vs_sync_state & IP_VS_STATE_MASTER) &&
>  	    (((cp->protocol != IPPROTO_TCP ||
>  	       cp->state == IP_VS_TCP_S_ESTABLISHED) &&
> -	      (atomic_read(&cp->in_pkts) % sysctl_ip_vs_sync_threshold[1]
> +	      (pkts % sysctl_ip_vs_sync_threshold[1]

It seems that proc_do_sync_threshold() should check whether this value
is zero. The current checks also look racy since incorrect values are
first updated, then overwritten again.

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] net: sk_free() should be allowed right after sk_alloc()
From: Eric Dumazet @ 2009-08-31 12:12 UTC (permalink / raw)
  To: David Miller; +Cc: jarkao2, netdev
In-Reply-To: <20090831.050220.255723045.davem@davemloft.net>

David Miller a écrit :
> From: Jarek Poplawski <jarkao2@gmail.com>
> Date: Mon, 31 Aug 2009 09:30:19 +0000
> 
>> On Mon, Aug 31, 2009 at 11:15:36AM +0200, Eric Dumazet wrote:
>>> From: Jarek Poplawski <jarkao2@gmail.com>
>>>
>>> After commit 2b85a34e911bf483c27cfdd124aeb1605145dc80
>>> (net: No more expensive sock_hold()/sock_put() on each tx)
>>> sk_free() frees socks conditionally and depends
>>> on sk_wmem_alloc beeing set e.g. in sock_init_data(). But in some
>> Very nice, but I hope David could fix btw. my "beeing" misspelling.
> 
> I will :-)

Thanks :)


^ permalink raw reply

* Re: [PATCH net-next-2.6] ip: Report qdisc packet drops
From: Eric Dumazet @ 2009-08-31 12:09 UTC (permalink / raw)
  To: David Miller; +Cc: cl, sri, dlstevens, netdev, niv, mtk.manpages
In-Reply-To: <20090828.233858.256193304.davem@davemloft.net>

David Miller a écrit :
> From: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Fri, 28 Aug 2009 19:26:04 +0200
> 
>> [PATCH] ip: Report qdisc packet drops
>>
>> Christoph Lameter pointed out that packet drops at qdisc level where not
>> accounted in SNMP counters. Only if application sets IP_RECVERR, drops
>> are reported to user and SNMP counters updated.
>>
>> IP_RECVERR is used to enable extended reliable error message passing.
>> In case of tx drops at qdisc level, no error packet will be generated.
>> It seems un-necessary to hide the qdisc drops for non IP_RECVERR enabled
>> sockets (as probably most sockets are)
>>
>> By removing the check of IP_RECVERR enabled sockets in ip_push_pending_frames()/
>> raw_send_hdrinc() / ip6_push_pending_frames() / rawv6_send_hdrinc(),
>> we can properly update IPSTATS_MIB_OUTDISCARDS, and in case of UDP, update
>> UDP_MIB_SNDBUFERRORS SNMP counters.
>>
>> Application send() syscalls, instead of returning an OK status (thus lying),
>> will return -ENOBUFS error.
>>
>> Note : send() manual page explicitly says for -ENOBUFS error :
>>
>>  "The output queue for a network interface was full.
>>   This generally indicates that the interface has stopped sending,
>>   but may be caused by transient congestion.
>>   (Normally, this does not occur in Linux. Packets are just silently
>>   dropped when a device queue overflows.) "
>>
>> This was not true for IP_RECVERR enabled sockets for < 2.6.32 linuxes,
>> and starting from linux 2.6.32, last part wont be true at all.
>>
>> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
>> Signed-off-by: Christoph Lameter <cl@linux-foundation.org>
> 
> The core question in all of this is what IP_RECVERR means.
> 
> As far as I remember Alexey Kuznetsov's intentions, it means that the
> application is interested in learning about errors caused by the
> infrastructure of the network between local and remote stacks.
> 
> Reporting a qdisc level drop to the application by default has the
> potential to break applications, because BSD and other stacks do not
> do this.
> 
> I can see why we might be able to get away with making this change
> now.  And I also can see the benefits of it, for sure.
> 
> Let me think about this some more.

Yes I do agree this is risky.

Re-reading again this stuff, I realized ip6_push_pending_frames()
was not updating IPSTATS_MIB_OUTDISCARDS, even if IP_RECVERR was set.

May I suggest following path :

1) Correct ip6_push_pending_frames() to properly
account for dropped-by-qdisc frames when IP_RECVERR is set

2) Submit a patch to account for qdisc-dropped frames in SNMP counters
but still return a OK to user application, to not break them ?

Thanks

[PATCH] ipv6: ip6_push_pending_frames() should increment IPSTATS_MIB_OUTDISCARDS

qdisc drops should be notified to IP_RECVERR enabled sockets, as done in IPV4.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 6ad5aad..a931229 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1520,6 +1520,7 @@ out:
 	ip6_cork_release(inet, np);
 	return err;
 error:
+	IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
 	goto out;
 }
 

^ permalink raw reply related

* Re: [PATCH] net: sk_free() should be allowed right after sk_alloc()
From: David Miller @ 2009-08-31 12:02 UTC (permalink / raw)
  To: jarkao2; +Cc: eric.dumazet, netdev
In-Reply-To: <20090831093019.GI5005@ff.dom.local>

From: Jarek Poplawski <jarkao2@gmail.com>
Date: Mon, 31 Aug 2009 09:30:19 +0000

> On Mon, Aug 31, 2009 at 11:15:36AM +0200, Eric Dumazet wrote:
>> From: Jarek Poplawski <jarkao2@gmail.com>
>> 
>> After commit 2b85a34e911bf483c27cfdd124aeb1605145dc80
>> (net: No more expensive sock_hold()/sock_put() on each tx)
>> sk_free() frees socks conditionally and depends
>> on sk_wmem_alloc beeing set e.g. in sock_init_data(). But in some
> 
> Very nice, but I hope David could fix btw. my "beeing" misspelling.

I will :-)

^ permalink raw reply

* Re: [PATCH resend] drop_monitor: fix trace_napi_poll_hit()
From: David Miller @ 2009-08-31 11:47 UTC (permalink / raw)
  To: nhorman; +Cc: eric.dumazet, xiaoguangrong, yjwei, netdev, linux-kernel
In-Reply-To: <20090831111245.GA2105@hmsreliant.think-freely.org>

From: Neil Horman <nhorman@tuxdriver.com>
Date: Mon, 31 Aug 2009 07:12:46 -0400

> If its not going to be consistently updated, why are still carrying
> that field in dev?  Are we just waiting on someone to do the
> janitorial work to remove it?  If so, I can, and I'll fix up the
> drop monitor in the process, to use a private timestamp.

It's used only for bonding, so we only update it when a device
receives packet as part of a bond.

%99.9999 of people are not in that situation, and in that case this is
a very wasteful and expensive cacheline dirtying, so we elide it when
we can.

^ permalink raw reply

* RE: [PATCHv5 3/3] vhost_net: a kernel-level virtio server
From: Xin, Xiaohui @ 2009-08-31 11:42 UTC (permalink / raw)
  To: mst@redhat.com, netdev@vger.kernel.org,
	virtualization@lists.linux-foundation.org, "kvm@v
In-Reply-To: <E88DD564E9DC5446A76B2B47C3BCCA150219600F9B@pdsmsx503.ccr.corp.intel.com>

Hi, Michael
That's a great job. We are now working on support VMDq on KVM, and since the VMDq hardware presents L2 sorting based on MAC addresses and VLAN tags, our target is to implement a zero copy solution using VMDq. We stared from the virtio-net architecture. What we want to proposal is to use AIO combined with direct I/O:
1) Modify virtio-net Backend service in Qemu to submit aio requests composed from virtqueue.
2) Modify TUN/TAP device to support aio operations and the user space buffer directly mapping into the host kernel.
3) Let a TUN/TAP device binds to single rx/tx queue from the NIC.
4) Modify the net_dev and skb structure to permit allocated skb to use user space directly mapped payload buffer address rather then kernel allocated.

As zero copy is also your goal, we are interested in what's in your mind, and would like to collaborate with you if possible.
BTW, we will send our VMDq write-up very soon.

Thanks
Xiaohui

-----Original Message-----
From: kvm-owner@vger.kernel.org [mailto:kvm-owner@vger.kernel.org] On Behalf Of Michael S. Tsirkin
Sent: Wednesday, August 19, 2009 11:03 PM
To: netdev@vger.kernel.org; virtualization@lists.linux-foundation.org; kvm@vger.kernel.org; linux-kernel@vger.kernel.org; mingo@elte.hu; linux-mm@kvack.org; akpm@linux-foundation.org; hpa@zytor.com; gregory.haskins@gmail.com
Subject: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

What it is: vhost net is a character device that can be used to reduce
the number of system calls involved in virtio networking.
Existing virtio net code is used in the guest without modification.

There's similarity with vringfd, with some differences and reduced scope
- uses eventfd for signalling
- structures can be moved around in memory at any time (good for migration)
- support memory table and not just an offset (needed for kvm)

common virtio related code has been put in a separate file vhost.c and
can be made into a separate module if/when more backends appear.  I used
Rusty's lguest.c as the source for developing this part : this supplied
me with witty comments I wouldn't be able to write myself.

What it is not: vhost net is not a bus, and not a generic new system
call. No assumptions are made on how guest performs hypercalls.
Userspace hypervisors are supported as well as kvm.

How it works: Basically, we connect virtio frontend (configured by
userspace) to a backend. The backend could be a network device, or a
tun-like device. In this version I only support raw socket as a backend,
which can be bound to e.g. SR IOV, or to macvlan device.  Backend is
also configured by userspace, including vlan/mac etc.

Status:
This works for me, and I haven't see any crashes.
I have not run any benchmarks yet, compared to userspace, I expect to
see improved latency (as I save up to 4 system calls per packet) but not
bandwidth/CPU (as TSO and interrupt mitigation are not supported).

Features that I plan to look at in the future:
- TSO
- interrupt mitigation
- zero copy

Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 MAINTAINERS                |   10 +
 arch/x86/kvm/Kconfig       |    1 +
 drivers/Makefile           |    1 +
 drivers/vhost/Kconfig      |   11 +
 drivers/vhost/Makefile     |    2 +
 drivers/vhost/net.c        |  429 ++++++++++++++++++++++++++++
 drivers/vhost/vhost.c      |  664 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/vhost/vhost.h      |  108 +++++++
 include/linux/Kbuild       |    1 +
 include/linux/miscdevice.h |    1 +
 include/linux/vhost.h      |  100 +++++++
 11 files changed, 1328 insertions(+), 0 deletions(-)
 create mode 100644 drivers/vhost/Kconfig
 create mode 100644 drivers/vhost/Makefile
 create mode 100644 drivers/vhost/net.c
 create mode 100644 drivers/vhost/vhost.c
 create mode 100644 drivers/vhost/vhost.h
 create mode 100644 include/linux/vhost.h

diff --git a/MAINTAINERS b/MAINTAINERS
index b1114cf..de4587f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5431,6 +5431,16 @@ S:       Maintained
 F:     Documentation/filesystems/vfat.txt
 F:     fs/fat/

+VIRTIO HOST (VHOST)
+P:     Michael S. Tsirkin
+M:     mst@redhat.com
+L:     kvm@vger.kernel.org
+L:     virtualization@lists.osdl.org
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/vhost/
+F:     include/linux/vhost.h
+
 VIA RHINE NETWORK DRIVER
 M:     Roger Luethi <rl@hellgate.ch>
 S:     Maintained
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index b84e571..94f44d9 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -64,6 +64,7 @@ config KVM_AMD

 # OK, it's a little counter-intuitive to do this, but it puts it neatly under
 # the virtualization menu.
+source drivers/vhost/Kconfig
 source drivers/lguest/Kconfig
 source drivers/virtio/Kconfig

diff --git a/drivers/Makefile b/drivers/Makefile
index bc4205d..1551ae1 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -105,6 +105,7 @@ obj-$(CONFIG_HID)           += hid/
 obj-$(CONFIG_PPC_PS3)          += ps3/
 obj-$(CONFIG_OF)               += of/
 obj-$(CONFIG_SSB)              += ssb/
+obj-$(CONFIG_VHOST_NET)                += vhost/
 obj-$(CONFIG_VIRTIO)           += virtio/
 obj-$(CONFIG_VLYNQ)            += vlynq/
 obj-$(CONFIG_STAGING)          += staging/
diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig
new file mode 100644
index 0000000..d955406
--- /dev/null
+++ b/drivers/vhost/Kconfig
@@ -0,0 +1,11 @@
+config VHOST_NET
+       tristate "Host kernel accelerator for virtio net"
+       depends on NET && EVENTFD
+       ---help---
+         This kernel module can be loaded in host kernel to accelerate
+         guest networking with virtio_net. Not to be confused with virtio_net
+         module itself which needs to be loaded in guest kernel.
+
+         To compile this driver as a module, choose M here: the module will
+         be called vhost_net.
+
diff --git a/drivers/vhost/Makefile b/drivers/vhost/Makefile
new file mode 100644
index 0000000..72dd020
--- /dev/null
+++ b/drivers/vhost/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VHOST_NET) += vhost_net.o
+vhost_net-y := vhost.o net.o
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
new file mode 100644
index 0000000..64d0c13
--- /dev/null
+++ b/drivers/vhost/net.c
@@ -0,0 +1,429 @@
+/* Copyright (C) 2009 Red Hat, Inc.
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * virtio-net server in host kernel.
+ */
+
+#include <linux/compat.h>
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/virtio_net.h>
+#include <linux/mmu_context.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/rcupdate.h>
+#include <linux/file.h>
+
+#include <linux/net.h>
+#include <linux/if_packet.h>
+#include <linux/if_arp.h>
+
+#include <net/sock.h>
+
+#include "vhost.h"
+
+enum {
+       VHOST_NET_VQ_RX = 0,
+       VHOST_NET_VQ_TX = 1,
+       VHOST_NET_VQ_MAX = 2,
+};
+
+struct vhost_net {
+       struct vhost_dev dev;
+       struct vhost_virtqueue vqs[VHOST_NET_VQ_MAX];
+       /* We use a kind of RCU to access sock pointer.
+        * All readers access it from workqueue, which makes it possible to
+        * flush the workqueue instead of synchronize_rcu. Therefore readers do
+        * not need to call rcu_read_lock/rcu_read_unlock: the beginning of
+        * work item execution acts instead of rcu_read_lock() and the end of
+        * work item execution acts instead of rcu_read_lock().
+        * Writers use device mutex. */
+       struct socket *sock;
+       struct vhost_poll poll[VHOST_NET_VQ_MAX];
+};
+
+/* Expects to be always run from workqueue - which acts as
+ * read-size critical section for our kind of RCU. */
+static void handle_tx(struct vhost_net *net)
+{
+       struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
+       unsigned head, out, in;
+       struct msghdr msg = {
+               .msg_name = NULL,
+               .msg_namelen = 0,
+               .msg_control = NULL,
+               .msg_controllen = 0,
+               .msg_iov = (struct iovec *)vq->iov + 1,
+               .msg_flags = MSG_DONTWAIT,
+       };
+       size_t len;
+       int err;
+       struct socket *sock = rcu_dereference(net->sock);
+       if (!sock || !sock_writeable(sock->sk))
+               return;
+
+       use_mm(net->dev.mm);
+       mutex_lock(&vq->mutex);
+       for (;;) {
+               head = vhost_get_vq_desc(&net->dev, vq, vq->iov, &out, &in);
+               /* Nothing new?  Wait for eventfd to tell us they refilled. */
+               if (head == vq->num)
+                       break;
+               if (out <= 1 || in) {
+                       vq_err(vq, "Unexpected descriptor format for TX: "
+                              "out %d, int %d\n", out, in);
+                       break;
+               }
+               /* Sanity check */
+               if (vq->iov->iov_len != sizeof(struct virtio_net_hdr)) {
+                       vq_err(vq, "Unexpected header len for TX: "
+                              "%ld expected %zd\n", vq->iov->iov_len,
+                              sizeof(struct virtio_net_hdr));
+                       break;
+               }
+               /* Skip header. TODO: support TSO. */
+               msg.msg_iovlen = out - 1;
+               len = iov_length(vq->iov + 1, out - 1);
+               /* TODO: Check specific error and bomb out unless ENOBUFS? */
+               err = sock->ops->sendmsg(NULL, sock, &msg, len);
+               if (err < 0) {
+                       vhost_discard_vq_desc(vq);
+                       break;
+               }
+               if (err != len)
+                       pr_err("Truncated TX packet: "
+                              " len %d != %zd\n", err, len);
+               vhost_add_used_and_trigger(vq, head,
+                                    len + sizeof(struct virtio_net_hdr));
+       }
+
+       mutex_unlock(&vq->mutex);
+       unuse_mm(net->dev.mm);
+}
+
+/* Expects to be always run from workqueue - which acts as
+ * read-size critical section for our kind of RCU. */
+static void handle_rx(struct vhost_net *net)
+{
+       struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
+       unsigned head, out, in;
+       struct msghdr msg = {
+               .msg_name = NULL,
+               .msg_namelen = 0,
+               .msg_control = NULL, /* FIXME: get and handle RX aux data. */
+               .msg_controllen = 0,
+               .msg_iov = vq->iov + 1,
+               .msg_flags = MSG_DONTWAIT,
+       };
+
+       struct virtio_net_hdr hdr = {
+               .flags = 0,
+               .gso_type = VIRTIO_NET_HDR_GSO_NONE
+       };
+
+       size_t len;
+       int err;
+       struct socket *sock = rcu_dereference(net->sock);
+       if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
+               return;
+
+       use_mm(net->dev.mm);
+       mutex_lock(&vq->mutex);
+
+       for (;;) {
+               head = vhost_get_vq_desc(&net->dev, vq, vq->iov, &out, &in);
+               if (head == vq->num)
+                       break;
+               if (in <= 1 || out) {
+                       vq_err(vq, "Unexpected descriptor format for RX: "
+                              "out %d, int %d\n",
+                              out, in);
+                       break;
+               }
+               /* Sanity check */
+               if (vq->iov->iov_len != sizeof(struct virtio_net_hdr)) {
+                       vq_err(vq, "Unexpected header len for RX: "
+                              "%ld expected %zd\n",
+                              vq->iov->iov_len, sizeof(struct virtio_net_hdr));
+                       break;
+               }
+               /* Skip header. TODO: support TSO/mergeable rx buffers. */
+               msg.msg_iovlen = in - 1;
+               len = iov_length(vq->iov + 1, in - 1);
+               err = sock->ops->recvmsg(NULL, sock, &msg,
+                                        len, MSG_DONTWAIT | MSG_TRUNC);
+               /* TODO: Check specific error and bomb out unless EAGAIN? */
+               if (err < 0) {
+                       vhost_discard_vq_desc(vq);
+                       break;
+               }
+               /* TODO: Should check and handle checksum. */
+               if (err > len) {
+                       pr_err("Discarded truncated rx packet: "
+                              " len %d > %zd\n", err, len);
+                       vhost_discard_vq_desc(vq);
+                       continue;
+               }
+               len = err;
+               err = copy_to_user(vq->iov->iov_base, &hdr, sizeof hdr);
+               if (err) {
+                       vq_err(vq, "Unable to write vnet_hdr at addr %p: %d\n",
+                              vq->iov->iov_base, err);
+                       break;
+               }
+               vhost_add_used_and_trigger(vq, head, len + sizeof hdr);
+       }
+
+       mutex_unlock(&vq->mutex);
+       unuse_mm(net->dev.mm);
+}
+
+static void handle_tx_kick(struct work_struct *work)
+{
+       struct vhost_virtqueue *vq;
+       struct vhost_net *net;
+       vq = container_of(work, struct vhost_virtqueue, poll.work);
+       net = container_of(vq->dev, struct vhost_net, dev);
+       handle_tx(net);
+}
+
+static void handle_rx_kick(struct work_struct *work)
+{
+       struct vhost_virtqueue *vq;
+       struct vhost_net *net;
+       vq = container_of(work, struct vhost_virtqueue, poll.work);
+       net = container_of(vq->dev, struct vhost_net, dev);
+       handle_rx(net);
+}
+
+static void handle_tx_net(struct work_struct *work)
+{
+       struct vhost_net *net;
+       net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_TX].work);
+       handle_tx(net);
+}
+
+static void handle_rx_net(struct work_struct *work)
+{
+       struct vhost_net *net;
+       net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_RX].work);
+       handle_rx(net);
+}
+
+static int vhost_net_open(struct inode *inode, struct file *f)
+{
+       struct vhost_net *n = kzalloc(sizeof *n, GFP_KERNEL);
+       int r;
+       if (!n)
+               return -ENOMEM;
+       f->private_data = n;
+       n->vqs[VHOST_NET_VQ_TX].handle_kick = handle_tx_kick;
+       n->vqs[VHOST_NET_VQ_RX].handle_kick = handle_rx_kick;
+       r = vhost_dev_init(&n->dev, n->vqs, VHOST_NET_VQ_MAX);
+       if (r < 0) {
+               kfree(n);
+               return r;
+       }
+
+       vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, POLLOUT);
+       vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, POLLIN);
+       return 0;
+}
+
+static struct socket *vhost_net_stop(struct vhost_net *n)
+{
+       struct socket *sock = n->sock;
+       rcu_assign_pointer(n->sock, NULL);
+       if (sock) {
+               vhost_poll_flush(n->poll + VHOST_NET_VQ_TX);
+               vhost_poll_flush(n->poll + VHOST_NET_VQ_RX);
+       }
+       return sock;
+}
+
+static int vhost_net_release(struct inode *inode, struct file *f)
+{
+       struct vhost_net *n = f->private_data;
+       struct socket *sock;
+
+       sock = vhost_net_stop(n);
+       vhost_dev_cleanup(&n->dev);
+       if (sock)
+               fput(sock->file);
+       kfree(n);
+       return 0;
+}
+
+static long vhost_net_set_socket(struct vhost_net *n, int fd)
+{
+       struct {
+               struct sockaddr_ll sa;
+               char  buf[MAX_ADDR_LEN];
+       } uaddr;
+       struct socket *sock, *oldsock = NULL;
+       int uaddr_len = sizeof uaddr, r;
+
+       mutex_lock(&n->dev.mutex);
+       r = vhost_dev_check_owner(&n->dev);
+       if (r)
+               goto done;
+
+       if (fd == -1) {
+               /* Disconnect from socket and device. */
+               oldsock = vhost_net_stop(n);
+               goto done;
+       }
+
+       sock = sockfd_lookup(fd, &r);
+       if (!sock) {
+               r = -ENOTSOCK;
+               goto done;
+       }
+
+       /* Parameter checking */
+       if (sock->sk->sk_type != SOCK_RAW) {
+               r = -ESOCKTNOSUPPORT;
+               goto done;
+       }
+
+       r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa,
+                              &uaddr_len, 0);
+       if (r)
+               goto done;
+
+       if (uaddr.sa.sll_family != AF_PACKET) {
+               r = -EPFNOSUPPORT;
+               goto done;
+       }
+
+       /* start polling new socket */
+       if (sock == oldsock)
+               goto done;
+
+       if (oldsock) {
+               vhost_poll_stop(n->poll + VHOST_NET_VQ_TX);
+               vhost_poll_stop(n->poll + VHOST_NET_VQ_RX);
+       }
+       oldsock = n->sock;
+       rcu_assign_pointer(n->sock, sock);
+       vhost_poll_start(n->poll + VHOST_NET_VQ_TX, sock->file);
+       vhost_poll_start(n->poll + VHOST_NET_VQ_RX, sock->file);
+done:
+       mutex_unlock(&n->dev.mutex);
+       if (oldsock) {
+               vhost_poll_flush(n->poll + VHOST_NET_VQ_TX);
+               vhost_poll_flush(n->poll + VHOST_NET_VQ_RX);
+               vhost_poll_flush(&n->dev.vqs[VHOST_NET_VQ_TX].poll);
+               vhost_poll_flush(&n->dev.vqs[VHOST_NET_VQ_RX].poll);
+               fput(oldsock->file);
+       }
+       return r;
+}
+
+static long vhost_net_reset_owner(struct vhost_net *n)
+{
+       struct socket *sock = NULL;
+       long r;
+       mutex_lock(&n->dev.mutex);
+       r = vhost_dev_check_owner(&n->dev);
+       if (r)
+               goto done;
+       sock = vhost_net_stop(n);
+       r = vhost_dev_reset_owner(&n->dev);
+done:
+       mutex_unlock(&n->dev.mutex);
+       if (sock)
+               fput(sock->file);
+       return r;
+}
+
+static long vhost_net_ioctl(struct file *f, unsigned int ioctl,
+                           unsigned long arg)
+{
+       struct vhost_net *n = f->private_data;
+       void __user *argp = (void __user *)arg;
+       u32 __user *featurep = argp;
+       int __user *fdp = argp;
+       u32 features;
+       int fd, r;
+       switch (ioctl) {
+       case VHOST_NET_SET_SOCKET:
+               r = get_user(fd, fdp);
+               if (r < 0)
+                       return r;
+               return vhost_net_set_socket(n, fd);
+       case VHOST_GET_FEATURES:
+               /* No features for now */
+               features = 0;
+               return put_user(features, featurep);
+       case VHOST_ACK_FEATURES:
+               r = get_user(features, featurep);
+               /* No features for now */
+               if (r < 0)
+                       return r;
+               if (features)
+                       return -EOPNOTSUPP;
+               return 0;
+       case VHOST_RESET_OWNER:
+               return vhost_net_reset_owner(n);
+       default:
+               return vhost_dev_ioctl(&n->dev, ioctl, arg);
+       }
+}
+
+#ifdef CONFIG_COMPAT
+static long vhost_net_compat_ioctl(struct file *f, unsigned int ioctl,
+                                  unsigned long arg)
+{
+       return vhost_net_ioctl(f, ioctl, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+const static struct file_operations vhost_net_fops = {
+       .owner          = THIS_MODULE,
+       .release        = vhost_net_release,
+       .unlocked_ioctl = vhost_net_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = vhost_net_compat_ioctl,
+#endif
+       .open           = vhost_net_open,
+};
+
+static struct miscdevice vhost_net_misc = {
+       VHOST_NET_MINOR,
+       "vhost-net",
+       &vhost_net_fops,
+};
+
+int vhost_net_init(void)
+{
+       int r = vhost_init();
+       if (r)
+               goto err_init;
+       r = misc_register(&vhost_net_misc);
+       if (r)
+               goto err_reg;
+       return 0;
+err_reg:
+       vhost_cleanup();
+err_init:
+       return r;
+
+}
+module_init(vhost_net_init);
+
+void vhost_net_exit(void)
+{
+       misc_deregister(&vhost_net_misc);
+       vhost_cleanup();
+}
+module_exit(vhost_net_exit);
+
+MODULE_VERSION("0.0.1");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Michael S. Tsirkin");
+MODULE_DESCRIPTION("Host kernel accelerator for virtio net");
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
new file mode 100644
index 0000000..e14169f
--- /dev/null
+++ b/drivers/vhost/vhost.c
@@ -0,0 +1,664 @@
+/* Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2006 Rusty Russell IBM Corporation
+ *
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * Inspiration, some code, and most witty comments come from
+ * Documentation/lguest/lguest.c, by Rusty Russell
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * Generic code for virtio server in host kernel.
+ */
+
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/virtio_net.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/rcupdate.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+
+#include <linux/net.h>
+#include <linux/if_packet.h>
+#include <linux/if_arp.h>
+
+#include <net/sock.h>
+
+#include "vhost.h"
+
+enum {
+       VHOST_MEMORY_MAX_NREGIONS = 64,
+};
+
+static struct workqueue_struct *vhost_workqueue;
+
+static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh,
+                           poll_table *pt)
+{
+       struct vhost_poll *poll;
+       poll = container_of(pt, struct vhost_poll, table);
+
+       poll->wqh = wqh;
+       add_wait_queue(wqh, &poll->wait);
+}
+
+static int vhost_poll_wakeup(wait_queue_t *wait, unsigned mode, int sync,
+                            void *key)
+{
+       struct vhost_poll *poll;
+       poll = container_of(wait, struct vhost_poll, wait);
+       if (!((unsigned long)key & poll->mask))
+               return 0;
+
+       queue_work(vhost_workqueue, &poll->work);
+       return 0;
+}
+
+/* Init poll structure */
+void vhost_poll_init(struct vhost_poll *poll, work_func_t func,
+                    unsigned long mask)
+{
+       INIT_WORK(&poll->work, func);
+       init_waitqueue_func_entry(&poll->wait, vhost_poll_wakeup);
+       init_poll_funcptr(&poll->table, vhost_poll_func);
+       poll->mask = mask;
+}
+
+/* Start polling a file. We add ourselves to file's wait queue. The user must
+ * keep a reference to a file until after vhost_poll_stop is called. */
+void vhost_poll_start(struct vhost_poll *poll, struct file *file)
+{
+       unsigned long mask;
+       mask = file->f_op->poll(file, &poll->table);
+       if (mask)
+               vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask);
+}
+
+/* Stop polling a file. After this function returns, it becomes safe to drop the
+ * file reference. You must also flush afterwards. */
+void vhost_poll_stop(struct vhost_poll *poll)
+{
+       remove_wait_queue(poll->wqh, &poll->wait);
+}
+
+/* Flush any work that has been scheduled. When calling this, don't hold any
+ * locks that are also used by the callback. */
+void vhost_poll_flush(struct vhost_poll *poll)
+{
+       flush_work(&poll->work);
+}
+
+long vhost_dev_init(struct vhost_dev *dev,
+                   struct vhost_virtqueue *vqs, int nvqs)
+{
+       int i;
+       dev->vqs = vqs;
+       dev->nvqs = nvqs;
+       mutex_init(&dev->mutex);
+
+       for (i = 0; i < dev->nvqs; ++i) {
+               dev->vqs[i].dev = dev;
+               mutex_init(&dev->vqs[i].mutex);
+               if (dev->vqs[i].handle_kick)
+                       vhost_poll_init(&dev->vqs[i].poll,
+                                       dev->vqs[i].handle_kick,
+                                       POLLIN);
+       }
+       return 0;
+}
+
+/* User should have device mutex */
+long vhost_dev_check_owner(struct vhost_dev *dev)
+{
+       return dev->mm == current->mm ? 0 : -EPERM;
+}
+
+/* User should have device mutex */
+static long vhost_dev_set_owner(struct vhost_dev *dev)
+{
+       if (dev->mm)
+               return -EBUSY;
+       dev->mm = get_task_mm(current);
+       return 0;
+}
+
+/* User should have device mutex */
+long vhost_dev_reset_owner(struct vhost_dev *dev)
+{
+       struct vhost_memory *memory;
+
+       /* Restore memory to default 1:1 mapping. */
+       memory = kmalloc(offsetof(struct vhost_memory, regions) +
+                        2 * sizeof *memory->regions, GFP_KERNEL);
+       if (!memory)
+               return -ENOMEM;
+
+       vhost_dev_cleanup(dev);
+
+       memory->nregions = 2;
+       memory->regions[0].guest_phys_addr = 1;
+       memory->regions[0].userspace_addr = 1;
+       memory->regions[0].memory_size = ~0ULL;
+       memory->regions[1].guest_phys_addr = 0;
+       memory->regions[1].userspace_addr = 0;
+       memory->regions[1].memory_size = 1;
+       dev->memory = memory;
+       return 0;
+}
+
+/* User should have device mutex */
+void vhost_dev_cleanup(struct vhost_dev *dev)
+{
+       int i;
+       for (i = 0; i < dev->nvqs; ++i) {
+               if (dev->vqs[i].kick && dev->vqs[i].handle_kick) {
+                       vhost_poll_stop(&dev->vqs[i].poll);
+                       vhost_poll_flush(&dev->vqs[i].poll);
+               }
+               if (dev->vqs[i].error_ctx)
+                       eventfd_ctx_put(dev->vqs[i].error_ctx);
+               if (dev->vqs[i].error)
+                       fput(dev->vqs[i].error);
+               if (dev->vqs[i].kick)
+                       fput(dev->vqs[i].kick);
+               if (dev->vqs[i].call_ctx)
+                       eventfd_ctx_put(dev->vqs[i].call_ctx);
+               if (dev->vqs[i].call)
+                       fput(dev->vqs[i].call);
+               dev->vqs[i].error_ctx = NULL;
+               dev->vqs[i].error = NULL;
+               dev->vqs[i].kick = NULL;
+               dev->vqs[i].call_ctx = NULL;
+               dev->vqs[i].call = NULL;
+       }
+       /* No one will access memory at this point */
+       kfree(dev->memory);
+       dev->memory = NULL;
+       if (dev->mm)
+               mmput(dev->mm);
+       dev->mm = NULL;
+}
+
+static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
+{
+       struct vhost_memory mem, *newmem, *oldmem;
+       unsigned long size = offsetof(struct vhost_memory, regions);
+       long r;
+       r = copy_from_user(&mem, m, size);
+       if (r)
+               return r;
+       if (mem.padding)
+               return -EOPNOTSUPP;
+       if (mem.nregions > VHOST_MEMORY_MAX_NREGIONS)
+               return -E2BIG;
+       newmem = kmalloc(size + mem.nregions * sizeof *m->regions, GFP_KERNEL);
+       if (!newmem)
+               return -ENOMEM;
+
+       memcpy(newmem, &mem, size);
+       r = copy_from_user(newmem->regions, m->regions,
+                          mem.nregions * sizeof *m->regions);
+       if (r) {
+               kfree(newmem);
+               return r;
+       }
+       oldmem = d->memory;
+       rcu_assign_pointer(d->memory, newmem);
+       synchronize_rcu();
+       kfree(oldmem);
+       return 0;
+}
+
+static int init_used(struct vhost_virtqueue *vq)
+{
+       u16 flags = 0;
+       int r = put_user(flags, &vq->used->flags);
+       if (r)
+               return r;
+       return get_user(vq->last_used_idx, &vq->used->idx);
+}
+
+static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
+{
+       struct file *eventfp, *filep = NULL,
+                   *pollstart = NULL, *pollstop = NULL;
+       struct eventfd_ctx *ctx = NULL;
+       u32 __user *idxp = argp;
+       struct vhost_virtqueue *vq;
+       struct vhost_vring_state s;
+       struct vhost_vring_file f;
+       struct vhost_vring_addr a;
+       u32 idx;
+       long r;
+
+       r = get_user(idx, idxp);
+       if (r < 0)
+               return r;
+       if (idx > d->nvqs)
+               return -ENOBUFS;
+
+       vq = d->vqs + idx;
+
+       mutex_lock(&vq->mutex);
+
+       switch (ioctl) {
+       case VHOST_SET_VRING_NUM:
+               r = copy_from_user(&s, argp, sizeof s);
+               if (r < 0)
+                       break;
+               if (s.num > 0xffff) {
+                       r = -EINVAL;
+                       break;
+               }
+               vq->num = s.num;
+               break;
+       case VHOST_SET_VRING_BASE:
+               r = copy_from_user(&s, argp, sizeof s);
+               if (r < 0)
+                       break;
+               if (s.num > 0xffff) {
+                       r = -EINVAL;
+                       break;
+               }
+               vq->last_avail_idx = s.num;
+               break;
+       case VHOST_GET_VRING_BASE:
+               s.index = idx;
+               s.num = vq->last_avail_idx;
+               r = copy_to_user(argp, &s, sizeof s);
+               break;
+       case VHOST_SET_VRING_DESC:
+               r = copy_from_user(&a, argp, sizeof a);
+               if (r < 0)
+                       break;
+               if (a.padding) {
+                       r = -EOPNOTSUPP;
+                       break;
+               }
+               if ((u64)(long)a.user_addr != a.user_addr) {
+                       r = -EFAULT;
+                       break;
+               }
+               vq->desc = (void __user *)(long)a.user_addr;
+               break;
+       case VHOST_SET_VRING_AVAIL:
+               r = copy_from_user(&a, argp, sizeof a);
+               if (r < 0)
+                       break;
+               if (a.padding) {
+                       r = -EOPNOTSUPP;
+                       break;
+               }
+               if ((u64)(long)a.user_addr != a.user_addr) {
+                       r = -EFAULT;
+                       break;
+               }
+               vq->avail = (void __user *)(long)a.user_addr;
+               break;
+       case VHOST_SET_VRING_USED:
+               r = copy_from_user(&a, argp, sizeof a);
+               if (r < 0)
+                       break;
+               if (a.padding) {
+                       r = -EOPNOTSUPP;
+                       break;
+               }
+               if ((u64)(long)a.user_addr != a.user_addr) {
+                       r = -EFAULT;
+                       break;
+               }
+               vq->used = (void __user *)(long)a.user_addr;
+               r = init_used(vq);
+               if (r)
+                       break;
+               break;
+       case VHOST_SET_VRING_KICK:
+               r = copy_from_user(&f, argp, sizeof f);
+               if (r < 0)
+                       break;
+               eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
+               if (IS_ERR(eventfp))
+                       return PTR_ERR(eventfp);
+               if (eventfp != vq->kick) {
+                       pollstop = filep = vq->kick;
+                       pollstart = vq->kick = eventfp;
+               } else
+                       filep = eventfp;
+               break;
+       case VHOST_SET_VRING_CALL:
+               r = copy_from_user(&f, argp, sizeof f);
+               if (r < 0)
+                       break;
+               eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
+               if (IS_ERR(eventfp))
+                       return PTR_ERR(eventfp);
+               if (eventfp != vq->call) {
+                       filep = vq->call;
+                       ctx = vq->call_ctx;
+                       vq->call = eventfp;
+                       vq->call_ctx = eventfp ?
+                               eventfd_ctx_fileget(eventfp) : NULL;
+               } else
+                       filep = eventfp;
+               break;
+       case VHOST_SET_VRING_ERR:
+               r = copy_from_user(&f, argp, sizeof f);
+               if (r < 0)
+                       break;
+               eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
+               if (IS_ERR(eventfp))
+                       return PTR_ERR(eventfp);
+               if (eventfp != vq->error) {
+                       filep = vq->error;
+                       vq->error = eventfp;
+                       ctx = vq->error_ctx;
+                       vq->error_ctx = eventfp ?
+                               eventfd_ctx_fileget(eventfp) : NULL;
+               } else
+                       filep = eventfp;
+               break;
+       default:
+               r = -ENOIOCTLCMD;
+       }
+
+       if (pollstop && vq->handle_kick)
+               vhost_poll_stop(&vq->poll);
+
+       if (ctx)
+               eventfd_ctx_put(ctx);
+       if (filep)
+               fput(filep);
+
+       if (pollstart && vq->handle_kick)
+               vhost_poll_start(&vq->poll, vq->kick);
+
+       mutex_unlock(&vq->mutex);
+
+       if (pollstop && vq->handle_kick)
+               vhost_poll_flush(&vq->poll);
+       return 0;
+}
+
+long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       long r;
+
+       mutex_lock(&d->mutex);
+       if (ioctl == VHOST_SET_OWNER) {
+               r = vhost_dev_set_owner(d);
+               goto done;
+       }
+
+       r = vhost_dev_check_owner(d);
+       if (r)
+               goto done;
+
+       switch (ioctl) {
+       case VHOST_SET_MEM_TABLE:
+               r = vhost_set_memory(d, argp);
+               break;
+       default:
+               r = vhost_set_vring(d, ioctl, argp);
+               break;
+       }
+done:
+       mutex_unlock(&d->mutex);
+       return r;
+}
+
+static const struct vhost_memory_region *find_region(struct vhost_memory *mem,
+                                                    __u64 addr, __u32 len)
+{
+       struct vhost_memory_region *reg;
+       int i;
+       /* linear search is not brilliant, but we really have on the order of 6
+        * regions in practice */
+       for (i = 0; i < mem->nregions; ++i) {
+               reg = mem->regions + i;
+               if (reg->guest_phys_addr <= addr &&
+                   reg->guest_phys_addr + reg->memory_size - 1 >= addr)
+                       return reg;
+       }
+       return NULL;
+}
+
+/* FIXME: this does not handle a region that spans multiple
+ * address/len pairs */
+int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,
+                  struct iovec iov[], int iov_count, int iov_size,
+                  unsigned *num)
+{
+       const struct vhost_memory_region *reg;
+       struct vhost_memory *mem;
+       struct iovec *_iov;
+       u64 s = 0;
+       int ret = 0;
+
+       rcu_read_lock();
+
+       mem = rcu_dereference(dev->memory);
+       while ((u64)len > s) {
+               u64 size;
+               if (*num + iov_count >= iov_size) {
+                       ret = -ENOBUFS;
+                       break;
+               }
+               reg = find_region(mem, addr, len);
+               if (!reg) {
+                       ret = -EFAULT;
+                       break;
+               }
+               _iov = iov + iov_count + *num;
+               size = reg->memory_size - addr + reg->guest_phys_addr;
+               _iov->iov_len = min((u64)len, size);
+               _iov->iov_base = (void *)
+                       (reg->userspace_addr + addr - reg->guest_phys_addr);
+               s += size;
+               addr += size;
+               ++*num;
+       }
+
+       rcu_read_unlock();
+       return ret;
+}
+
+/* Each buffer in the virtqueues is actually a chain of descriptors.  This
+ * function returns the next descriptor in the chain, or vq->vring.num if we're
+ * at the end. */
+static unsigned next_desc(struct vhost_virtqueue *vq, struct vring_desc *desc)
+{
+       unsigned int next;
+
+       /* If this descriptor says it doesn't chain, we're done. */
+       if (!(desc->flags & VRING_DESC_F_NEXT))
+               return vq->num;
+
+       /* Check they're not leading us off end of descriptors. */
+       next = desc->next;
+       /* Make sure compiler knows to grab that: we don't want it changing! */
+       /* We will use the result as an index in an array, so most
+        * architectures only need a compiler barrier here. */
+       read_barrier_depends();
+
+       if (next >= vq->num) {
+               vq_err(vq, "Desc next is %u > %u", next, vq->num);
+               return vq->num;
+       }
+
+       return next;
+}
+
+/* This looks in the virtqueue and for the first available buffer, and converts
+ * it to an iovec for convenient access.  Since descriptors consist of some
+ * number of output then some number of input descriptors, it's actually two
+ * iovecs, but we pack them into one and note how many of each there were.
+ *
+ * This function returns the descriptor number found, or vq->num (which
+ * is never a valid descriptor number) if none was found. */
+unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
+                          struct iovec iov[],
+                          unsigned int *out_num, unsigned int *in_num)
+{
+       struct vring_desc desc;
+       unsigned int i, head;
+       u16 last_avail_idx, idx;
+
+       /* Check it isn't doing very strange things with descriptor numbers. */
+       last_avail_idx = vq->last_avail_idx;
+       if (get_user(idx, &vq->avail->idx)) {
+               vq_err(vq, "Failed to access avail idx at %p\n",
+                      &vq->avail->idx);
+               return vq->num;
+       }
+
+       if ((u16)(idx - last_avail_idx) > vq->num) {
+               vq_err(vq, "Guest moved used index from %u to %u",
+                      last_avail_idx, idx);
+               return vq->num;
+       }
+
+       /* If there's nothing new since last we looked, return invalid. */
+       if (idx == last_avail_idx)
+               return vq->num;
+
+       /* Grab the next descriptor number they're advertising, and increment
+        * the index we've seen. */
+       if (get_user(head, &vq->avail->ring[last_avail_idx % vq->num])) {
+               vq_err(vq, "Failed to read head: idx %d address %p\n",
+                      idx, &vq->avail->ring[last_avail_idx % vq->num]);
+               return vq->num;
+       }
+
+       /* If their number is silly, that's a fatal mistake. */
+       if (head >= vq->num) {
+               vq_err(vq, "Guest says index %u > %u is available",
+                      head, vq->num);
+               return vq->num;
+       }
+
+       vq->last_avail_idx++;
+
+       /* When we start there are none of either input nor output. */
+       *out_num = *in_num = 0;
+
+       i = head;
+       do {
+               unsigned *num;
+               unsigned iov_count;
+               if (copy_from_user(&desc, vq->desc + i, sizeof desc)) {
+                       vq_err(vq, "Failed to get descriptor: idx %d addr %p\n",
+                              i, vq->desc + i);
+                       return vq->num;
+               }
+               /* If this is an input descriptor, increment that count. */
+               if (desc.flags & VRING_DESC_F_WRITE) {
+                       num = in_num;
+                       iov_count = *out_num;
+               } else {
+                       /* If it's an output descriptor, they're all supposed
+                        * to come before any input descriptors. */
+                       if (*in_num) {
+                               vq_err(vq, "Descriptor has out after in: "
+                                      "idx %d\n", i);
+                               return vq->num;
+                       }
+                       num = out_num;
+                       iov_count = *in_num;
+               }
+               if (translate_desc(dev, desc.addr, desc.len, iov, iov_count,
+                                  VHOST_NET_MAX_SG, num)) {
+                       vq_err(vq, "Failed to translate descriptor: idx %d\n",
+                              i);
+                       return vq->num;
+               }
+
+               /* If we've got too many, that implies a descriptor loop. */
+               if (*out_num + *in_num > vq->num) {
+                       vq_err(vq, "Looped descriptor: idx %d\n", i);
+                       return vq->num;
+               }
+       } while ((i = next_desc(vq, &desc)) != vq->num);
+
+       vq->inflight++;
+       return head;
+}
+
+/* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
+void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
+{
+       vq->last_avail_idx--;
+       vq->inflight--;
+}
+
+/* After we've used one of their buffers, we tell them about it.  We'll then
+ * want to send them an interrupt, using vq->call. */
+int vhost_add_used(struct vhost_virtqueue *vq,
+                         unsigned int head, int len)
+{
+       struct vring_used_elem *used;
+
+       /* The virtqueue contains a ring of used buffers.  Get a pointer to the
+        * next entry in that used ring. */
+       used = &vq->used->ring[vq->last_used_idx % vq->num];
+       if (put_user(head, &used->id)) {
+               vq_err(vq, "Failed to write used id");
+               return -EFAULT;
+       }
+       if (put_user(len, &used->len)) {
+               vq_err(vq, "Failed to write used len");
+               return -EFAULT;
+       }
+       /* Make sure buffer is written before we update index. */
+       wmb();
+       if (put_user(vq->last_used_idx + 1, &vq->used->idx)) {
+               vq_err(vq, "Failed to increment used idx");
+               return -EFAULT;
+       }
+       vq->last_used_idx++;
+       vq->inflight--;
+       return 0;
+}
+
+/* This actually sends the interrupt for this virtqueue */
+void vhost_trigger_irq(struct vhost_virtqueue *vq)
+{
+       __u16 flags = 0;
+       if (get_user(flags, &vq->avail->flags)) {
+               vq_err(vq, "Failed to get flags");
+               return;
+       }
+
+       /* If they don't want an interrupt, don't send one, unless empty. */
+       if ((flags & VRING_AVAIL_F_NO_INTERRUPT) && vq->inflight)
+               return;
+
+       /* Send the Guest an interrupt tell them we used something up. */
+       if (vq->call_ctx)
+               eventfd_signal(vq->call_ctx, 1);
+}
+
+/* And here's the combo meal deal.  Supersize me! */
+void vhost_add_used_and_trigger(struct vhost_virtqueue *vq,
+                               unsigned int head, int len)
+{
+       vhost_add_used(vq, head, len);
+       vhost_trigger_irq(vq);
+}
+
+int vhost_init(void)
+{
+       vhost_workqueue = create_workqueue("vhost");
+       if (!vhost_workqueue)
+               return -ENOMEM;
+       return 0;
+}
+
+void vhost_cleanup(void)
+{
+       destroy_workqueue(vhost_workqueue);
+}
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
new file mode 100644
index 0000000..7f7ffcd
--- /dev/null
+++ b/drivers/vhost/vhost.h
@@ -0,0 +1,108 @@
+#ifndef _VHOST_H
+#define _VHOST_H
+
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+#include <linux/skbuff.h>
+
+struct vhost_device;
+
+enum {
+       VHOST_NET_MAX_SG = MAX_SKB_FRAGS + 2,
+};
+
+/* Poll a file (eventfd or socket) */
+/* Note: there's nothing vhost specific about this structure. */
+struct vhost_poll {
+       poll_table                table;
+       wait_queue_head_t        *wqh;
+       wait_queue_t              wait;
+       /* struct which will handle all actual work. */
+       struct work_struct        work;
+       unsigned long             mask;
+};
+
+void vhost_poll_init(struct vhost_poll *poll, work_func_t func,
+                    unsigned long mask);
+void vhost_poll_start(struct vhost_poll *poll, struct file *file);
+void vhost_poll_stop(struct vhost_poll *poll);
+void vhost_poll_flush(struct vhost_poll *poll);
+
+/* The virtqueue structure describes a queue attached to a device. */
+struct vhost_virtqueue {
+       struct vhost_dev *dev;
+
+       /* The actual ring of buffers. */
+       struct mutex mutex;
+       unsigned int num;
+       struct vring_desc __user *desc;
+       struct vring_avail __user *avail;
+       struct vring_used __user *used;
+       struct file *kick;
+       struct file *call;
+       struct file *error;
+       struct eventfd_ctx *call_ctx;
+       struct eventfd_ctx *error_ctx;
+
+       struct vhost_poll poll;
+
+       /* The routine to call when the Guest pings us, or timeout. */
+       work_func_t handle_kick;
+
+       /* Last available index we saw. */
+       u16 last_avail_idx;
+
+       /* Last index we used. */
+       u16 last_used_idx;
+
+       /* Outstanding buffers */
+       unsigned int inflight;
+
+       /* Is this blocked? */
+       bool blocked;
+
+       struct iovec iov[VHOST_NET_MAX_SG];
+
+} ____cacheline_aligned;
+
+struct vhost_dev {
+       /* Readers use RCU to access memory table pointer.
+        * Writers use mutex below.*/
+       struct vhost_memory *memory;
+       struct mm_struct *mm;
+       struct vhost_virtqueue *vqs;
+       int nvqs;
+       struct mutex mutex;
+};
+
+long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue *vqs, int nvqs);
+long vhost_dev_check_owner(struct vhost_dev *);
+long vhost_dev_reset_owner(struct vhost_dev *);
+void vhost_dev_cleanup(struct vhost_dev *);
+long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, unsigned long arg);
+
+unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *,
+                          struct iovec iov[],
+                          unsigned int *out_num, unsigned int *in_num);
+void vhost_discard_vq_desc(struct vhost_virtqueue *);
+
+int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
+void vhost_trigger_irq(struct vhost_virtqueue *);
+void vhost_add_used_and_trigger(struct vhost_virtqueue *,
+                               unsigned int head, int len);
+
+int vhost_init(void);
+void vhost_cleanup(void);
+
+#define vq_err(vq, fmt, ...) do {                                  \
+               printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__);       \
+               if ((vq)->error_ctx)                               \
+                               eventfd_signal((vq)->error_ctx, 1);\
+       } while (0)
+
+#endif
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index dec2f18..975df9a 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -360,6 +360,7 @@ unifdef-y += uio.h
 unifdef-y += unistd.h
 unifdef-y += usbdevice_fs.h
 unifdef-y += utsname.h
+unifdef-y += vhost.h
 unifdef-y += videodev2.h
 unifdef-y += videodev.h
 unifdef-y += virtio_config.h
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h
index 0521177..781a8bb 100644
--- a/include/linux/miscdevice.h
+++ b/include/linux/miscdevice.h
@@ -30,6 +30,7 @@
 #define HPET_MINOR             228
 #define FUSE_MINOR             229
 #define KVM_MINOR              232
+#define VHOST_NET_MINOR                233
 #define MISC_DYNAMIC_MINOR     255

 struct device;
diff --git a/include/linux/vhost.h b/include/linux/vhost.h
new file mode 100644
index 0000000..9ec6d5f
--- /dev/null
+++ b/include/linux/vhost.h
@@ -0,0 +1,100 @@
+#ifndef _LINUX_VHOST_H
+#define _LINUX_VHOST_H
+/* Userspace interface for in-kernel virtio accelerators. */
+
+/* vhost is used to reduce the number of system calls involved in virtio.
+ *
+ * Existing virtio net code is used in the guest without modification.
+ *
+ * This header includes interface used by userspace hypervisor for
+ * device configuration.
+ */
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/ioctl.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ring.h>
+
+struct vhost_vring_state {
+       unsigned int index;
+       unsigned int num;
+};
+
+struct vhost_vring_file {
+       unsigned int index;
+       int fd;
+};
+
+struct vhost_vring_addr {
+       unsigned int index;
+       unsigned int padding;
+       __u64 user_addr;
+};
+
+struct vhost_memory_region {
+       __u64 guest_phys_addr;
+       __u64 memory_size; /* bytes */
+       __u64 userspace_addr;
+       __u64 padding; /* read/write protection? */
+};
+
+struct vhost_memory {
+       __u32 nregions;
+       __u32 padding;
+       struct vhost_memory_region regions[0];
+};
+
+/* ioctls */
+
+#define VHOST_VIRTIO 0xAF
+
+/* Features bitmask for forward compatibility. Transport bits must be zero. */
+#define VHOST_GET_FEATURES     _IOR(VHOST_VIRTIO, 0x00, __u32)
+#define VHOST_ACK_FEATURES     _IOW(VHOST_VIRTIO, 0x00, __u32)
+
+/* Set current process as the (exclusive) owner of this file descriptor.  This
+ * must be called before any other vhost command.  Further calls to
+ * VHOST_OWNER_SET fail until VHOST_OWNER_RESET is called. */
+#define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01)
+/* Give up ownership, and reset the device to default values.
+ * Allows subsequent call to VHOST_OWNER_SET to succeed. */
+#define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02)
+
+/* Set up/modify memory layout */
+#define VHOST_SET_MEM_TABLE    _IOW(VHOST_VIRTIO, 0x03, struct vhost_memory)
+
+/* Ring setup. These parameters can not be modified while ring is running
+ * (bound to a device). */
+/* Set number of descriptors in ring */
+#define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state)
+/* Start of array of descriptors (virtually contiguous) */
+#define VHOST_SET_VRING_DESC _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr)
+/* Used structure address */
+#define VHOST_SET_VRING_USED _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_addr)
+/* Available structure address */
+#define VHOST_SET_VRING_AVAIL _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_addr)
+/* Base value where queue looks for available descriptors */
+#define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state)
+/* Get accessor: reads index, writes value in num */
+#define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x14, struct vhost_vring_state)
+
+/* The following ioctls use eventfd file descriptors to signal and poll
+ * for events. */
+
+/* Set eventfd to poll for added buffers */
+#define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file)
+/* Set eventfd to signal when buffers have beed used */
+#define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file)
+/* Set eventfd to signal an error */
+#define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file)
+
+/* VHOST_NET specific defines */
+
+/* Attach virtio net device to a raw socket. The socket must be already
+ * bound to an ethernet device, this device will be used for transmit.
+ * Pass -1 to unbind from the socket and the transmit device.
+ * This can be used to stop the device (e.g. for migration). */
+#define VHOST_NET_SET_SOCKET _IOW(VHOST_VIRTIO, 0x30, int)
+
+#endif
--
1.6.2.5
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related


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