* Re: [PATCH 0/4] skb paged fragment destructors
From: David Miller @ 2011-12-22 18:20 UTC (permalink / raw)
To: Ian.Campbell; +Cc: eric.dumazet, jesse.brandeburg, netdev
In-Reply-To: <1324550017.7877.77.camel@zakaz.uk.xensource.com>
From: Ian Campbell <Ian.Campbell@citrix.com>
Date: Thu, 22 Dec 2011 10:33:36 +0000
> On Wed, 2011-12-21 at 19:28 +0000, David Miller wrote:
>> From: Eric Dumazet <eric.dumazet@gmail.com>
>> Date: Wed, 21 Dec 2011 15:02:18 +0100
>>
>> > No idea on this +2 point.
>>
>> I think I know, and I believe I instructed Alexey Kuznetsov to do
>> this.
>>
>> When sendfile() is performed, we might start the SKB with the last few
>> bytes of one page, and end the SKB with the first few bytes of another
>> page.
>>
>> In order to fit a full 64K frame into an SKB in this situation we have
>> to accomodate this case.
>
> Thanks David, that makes sense.
>
> However I think you only actually need 1 extra page for that. If the
> data in frag[0] starts at $offset then frag[16] will need to have
> $offset bytes in it. e.g.
> 4096-$offset + 4096*15 + $offset = 65536
> which == 17 pages rather than 18.
>
> The following documents the status quo but I could update to switch to +
> 1 instead if there are no flaws in the above logic...
Indeed, you're right. Please change this to 1 and document it, and we
can put that change into net-next, thanks a lot!
^ permalink raw reply
* Re: BUG: unable to handle kernel NULL pointer dereference in ipv6_select_ident
From: Eric Dumazet @ 2011-12-22 17:41 UTC (permalink / raw)
To: Chris Boot; +Cc: David Miller, lkml, netdev, Steffen Klassert
In-Reply-To: <4EF352A2.2090604@bootc.net>
Le jeudi 22 décembre 2011 à 15:54 +0000, Chris Boot a écrit :
> Eric,
>
> I'm seeing a new problem now with IPv6 on my bridge, I don't know if
> it's related to any of the patches you gave me.
>
> Basically, I have eth0 and eth1 in a balance-rr bond (bond0), and this
> is added as a port in a bridge. When the bond and bridge are freshly
> brought up, IPv4 works fine but it appears to be deaf to IPv6 traffic.
> It stays this way until I run 'tcpdump -i eth0' and 'tcpdump -i eth1'.
> If I run tcpdump with the -p flag to not enable promiscuous mode, the
> interfaces remain deaf. Only if they enter promiscuous mode do they
> start to listen to each other. It also doesn't help to run tcpdump
> against bond0 or br0 at all.
>
> I'm not sure if once I've killed tcpdump they become deaf again, but I
> have enough IPv6 traffic to keep the neighbour entry alive.
Thats probably a separate issue. It would be better to open a new thread
on netdev, instead of continuing this one.
IPv6 needs multicast capabilities, so maybe balance-rr bonding mode is
not propagating multicat filters properly on both nics.
It might be a problem on one of your NIC.
(tcpdump automatically installs promiscous mode, so all multicast frames
are received, regardless of previous multicast filters in place)
^ permalink raw reply
* RE: [PATCH v2] ARM: net: JIT compiler for packet filters
From: David Laight @ 2011-12-22 17:34 UTC (permalink / raw)
To: Dave Martin, Mircea Gherzan; +Cc: linux-arm-kernel, netdev, linux
In-Reply-To: <20111222170006.GA2321@localhost>
> In principle, the condition could be __LINUX_ARM_ARCH__ < 5, since the
> bx instruction is guaranteed to be available on all ARMv5 CPUs and
> later (ARMv5T is not required).
Can't this code look at the actual cpu being used, and
generate the relevant 'return' instruction?
(Instead of trying to use some compile-time value.)
David
^ permalink raw reply
* Re: [PATCH v2] ARM: net: JIT compiler for packet filters
From: Dave Martin @ 2011-12-22 17:00 UTC (permalink / raw)
To: Mircea Gherzan; +Cc: linux-arm-kernel, netdev, linux
In-Reply-To: <20111221145913.GC3229@swarm.cs.pub.ro>
On Wed, Dec 21, 2011 at 04:59:13PM +0200, Mircea Gherzan wrote:
> On Mon, Dec 19, 2011 at 06:29:08PM +0000, Dave Martin wrote:
> > On Mon, Dec 19, 2011 at 06:18:39PM +0000, Dave Martin wrote:
> > > On Mon, Dec 19, 2011 at 06:45:13PM +0200, Mircea Gherzan wrote:
> >
> > [...]
> >
> > > > The JITed code calls back to the kernel for the load helpers. So setting
> > > > bit 0 is required.
> > >
> > > When you take the address of a link-time external function symbol,
> > > bit[0] in the address will automatically be set appropriately by the
> > > linker to indicate the target instruction set -- you already use BX/BLX
> > > to jump to such symbols, so you should switch correctly when calling
> > > _to_ the kernel.
> > >
> > > Returns should also work, except for old-style "mov pc,lr" returns made
> > > in Thumb code (from ARM code, this magically works for >= v7). Such returns
> > > only happen in hand-written assembler: for C code, the compiler always
> > > generates proper AEABI-compliant return sequences.
> > >
> > > So, for calling load_func[], jit_get_skb_b etc. (which are C functions),
> > > there should be no problem.
> > >
> > > I think the only code which you call from the JIT output but which does
> > > not return compliantly is __aeabi_uidiv() in arch/arm/lib/lib1funcs.S.
> > >
> > >
> > > I have a quick hacked-up patch (below) which attempts to fix this;
> > > I'd be interested if this works for you -- but finalising your ARM-only
> > > version of the patch should still be the priority.
> > >
> > > If this fix does work, I'll turn it into a proper patch, as we can maybe
> > > use it more widely.
> >
> > Oops, I forgot to paste in my patch ... here it is.
> >
> > Cheers
> > ---Dave
> >
> > diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
> > index b6e65de..013bfaf 100644
> > --- a/arch/arm/include/asm/assembler.h
> > +++ b/arch/arm/include/asm/assembler.h
> > @@ -313,4 +313,39 @@
> > .size \name , . - \name
> > .endm
> >
> > +/*
> > + * Helper macro to abstract a function return, where the return address is
> > + * held in a register:
> > + */
> > +.macro __def_bret cc
> > + .macro bret\cc Rm:req
> > +#if __LINUX_ARM_ARCH__ < 7
> > + mov\cc pc, \Rm
> > +#else
> > + bx\cc \Rm
> > +#endif
>
> This patch worked for me, because I'm using ARMv7 exclusively. But I'm
> inclined to think that your patch will fail on ARMv6T (for example) with
> a Thumb2 kernel, because the "mov pc, Rm" is a simple branch on pre-v7
> cores.
Thumb-2 kernels are not currently supported on ARMv6T2, and that's
probably not going to change for the foreseeable future. There are
not many v6T2 CPUs out there.
In principle, the condition could be __LINUX_ARM_ARCH__ < 5, since the
bx instruction is guaranteed to be available on all ARMv5 CPUs and
later (ARMv5T is not required).
For this sketch of the patch though, I just went for the principle of
least impact, and changed the behaviour only for CPUs where it's
definitely needed (i.e., v7+).
Thanks for trying it out, though.
> Note however that v3 of my patch no longer requires any changes to the
> assembly code: the C trampoline/wrapper for integer division ensures a
> proper return. And this one is used only for the DIV_X BPF opcode, which
> appears also quite rarely.
I may try to push my patch independently -- this way we might make
a lot of the existing assembler files properly EABI compliant at low
effort; as and when that happens, your C helper wouldn't be needed
any more, but it makes sense for you to keep if for now.
Cheers
---Dave
^ permalink raw reply
* Re: Invalid Argument when adding a bond to a bridge
From: Stephen Hemminger @ 2011-12-22 16:45 UTC (permalink / raw)
To: xmCM8KtKk25K; +Cc: NetDev, Bridge, Bonding Devel
In-Reply-To: <b8003b95089e177b00bc7db44700757a@pl1.haspere.com>
On Thu, 22 Dec 2011 08:25:54 -0600
Dyweni - NetDev <xmCM8KtKk25K@dyweni.com> wrote:
> Hi All,
>
> I need some help figuring this one out... Whenever I try to add a bond
> to a
> bridge, I get back an invalid argument error. I've confirmed this on
> 3.2-rc6, 3.1.5, 3.0.13, and 2.6.39.4 (haven't checked earlier kernels).
>
> Here's my setup: 32bit KVM virtual machine with no network cards (...
> -net
> none ... ).
>
> I created the bond with: echo "+x" > /sys/class/net/bonding_masters
>
> I created the bridge with: brctl addbr b
>
> I try to add the bond to the bridge with: brctl addif b x
>
The bonding device inherits its MAC address from the slave
devices. Therefore until the you add a slave to the bonding device
it's MAC address isn't set (all zeros). Bridging is not allowed
without a valid MAC address.
The solution is to fully configure the bonding device before adding
to the bridge.
^ permalink raw reply
* Re: BUG: unable to handle kernel NULL pointer dereference in ipv6_select_ident
From: Chris Boot @ 2011-12-22 15:54 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David Miller, lkml, netdev, Steffen Klassert
In-Reply-To: <1324563353.2153.27.camel@edumazet-HP-Compaq-6005-Pro-SFF-PC>
On 22/12/2011 14:15, Eric Dumazet wrote:
> Le jeudi 22 décembre 2011 à 10:04 +0000, Chris Boot a écrit :
>
>> Eric,
>>
>> So far so good. I've had this running for several hours this morning
>> with more of the prodding that would normally have crashed it, both IPv4
>> and IPv6, and it's holding up well.
>>
> Thanks for testing.
>
> Here is the official patch then (the .mtu() bit belongs to a separate
> patch)
>
> [PATCH] net: introduce DST_NOPEER dst flag
>
> Chris Boot reported crashes occurring in ipv6_select_ident().
>
> [ 461.457562] RIP: 0010:[<ffffffff812dde61>] [<ffffffff812dde61>]
> ipv6_select_ident+0x31/0xa7
>
> [ 461.578229] Call Trace:
> [ 461.580742]<IRQ>
> [ 461.582870] [<ffffffff812efa7f>] ? udp6_ufo_fragment+0x124/0x1a2
> [ 461.589054] [<ffffffff812dbfe0>] ? ipv6_gso_segment+0xc0/0x155
> [ 461.595140] [<ffffffff812700c6>] ? skb_gso_segment+0x208/0x28b
> [ 461.601198] [<ffffffffa03f236b>] ? ipv6_confirm+0x146/0x15e
> [nf_conntrack_ipv6]
> [ 461.608786] [<ffffffff81291c4d>] ? nf_iterate+0x41/0x77
> [ 461.614227] [<ffffffff81271d64>] ? dev_hard_start_xmit+0x357/0x543
> [ 461.620659] [<ffffffff81291cf6>] ? nf_hook_slow+0x73/0x111
> [ 461.626440] [<ffffffffa0379745>] ? br_parse_ip_options+0x19a/0x19a
> [bridge]
> [ 461.633581] [<ffffffff812722ff>] ? dev_queue_xmit+0x3af/0x459
> [ 461.639577] [<ffffffffa03747d2>] ? br_dev_queue_push_xmit+0x72/0x76
> [bridge]
> [ 461.646887] [<ffffffffa03791e3>] ? br_nf_post_routing+0x17d/0x18f
> [bridge]
> [ 461.653997] [<ffffffff81291c4d>] ? nf_iterate+0x41/0x77
> [ 461.659473] [<ffffffffa0374760>] ? br_flood+0xfa/0xfa [bridge]
> [ 461.665485] [<ffffffff81291cf6>] ? nf_hook_slow+0x73/0x111
> [ 461.671234] [<ffffffffa0374760>] ? br_flood+0xfa/0xfa [bridge]
> [ 461.677299] [<ffffffffa0379215>] ?
> nf_bridge_update_protocol+0x20/0x20 [bridge]
> [ 461.684891] [<ffffffffa03bb0e5>] ? nf_ct_zone+0xa/0x17 [nf_conntrack]
> [ 461.691520] [<ffffffffa0374760>] ? br_flood+0xfa/0xfa [bridge]
> [ 461.697572] [<ffffffffa0374812>] ? NF_HOOK.constprop.8+0x3c/0x56
> [bridge]
> [ 461.704616] [<ffffffffa0379031>] ?
> nf_bridge_push_encap_header+0x1c/0x26 [bridge]
> [ 461.712329] [<ffffffffa037929f>] ? br_nf_forward_finish+0x8a/0x95
> [bridge]
> [ 461.719490] [<ffffffffa037900a>] ?
> nf_bridge_pull_encap_header+0x1c/0x27 [bridge]
> [ 461.727223] [<ffffffffa0379974>] ? br_nf_forward_ip+0x1c0/0x1d4 [bridge]
> [ 461.734292] [<ffffffff81291c4d>] ? nf_iterate+0x41/0x77
> [ 461.739758] [<ffffffffa03748cc>] ? __br_deliver+0xa0/0xa0 [bridge]
> [ 461.746203] [<ffffffff81291cf6>] ? nf_hook_slow+0x73/0x111
> [ 461.751950] [<ffffffffa03748cc>] ? __br_deliver+0xa0/0xa0 [bridge]
> [ 461.758378] [<ffffffffa037533a>] ? NF_HOOK.constprop.4+0x56/0x56
> [bridge]
>
> This is caused by bridge netfilter special dst_entry (fake_rtable), a
> special shared entry, where attaching an inetpeer makes no sense.
>
> Problem is present since commit 87c48fa3b46 (ipv6: make fragment
> identifications less predictable)
>
> Introduce DST_NOPEER dst flag and make sure ipv6_select_ident() and
> __ip_select_ident() fallback to the 'no peer attached' handling.
>
> Reported-by: Chris Boot<bootc@bootc.net>
> Tested-by: Chris Boot<bootc@bootc.net>
> Signed-off-by: Eric Dumazet<eric.dumazet@gmail.com>
> ---
> include/net/dst.h | 1 +
> net/bridge/br_netfilter.c | 2 +-
> net/ipv4/route.c | 4 ++--
> net/ipv6/ip6_output.c | 2 +-
> 4 files changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/include/net/dst.h b/include/net/dst.h
> index 6faec1a..75766b4 100644
> --- a/include/net/dst.h
> +++ b/include/net/dst.h
> @@ -53,6 +53,7 @@ struct dst_entry {
> #define DST_NOHASH 0x0008
> #define DST_NOCACHE 0x0010
> #define DST_NOCOUNT 0x0020
> +#define DST_NOPEER 0x0040
>
> short error;
> short obsolete;
> diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
> index d6ec372..5693e5f 100644
> --- a/net/bridge/br_netfilter.c
> +++ b/net/bridge/br_netfilter.c
> @@ -141,7 +141,7 @@ void br_netfilter_rtable_init(struct net_bridge *br)
> rt->dst.dev = br->dev;
> rt->dst.path =&rt->dst;
> dst_init_metrics(&rt->dst, br_dst_default_metrics, true);
> - rt->dst.flags = DST_NOXFRM;
> + rt->dst.flags = DST_NOXFRM | DST_NOPEER;
> rt->dst.ops =&fake_dst_ops;
> }
>
> diff --git a/net/ipv4/route.c b/net/ipv4/route.c
> index 252c512..a5004f1 100644
> --- a/net/ipv4/route.c
> +++ b/net/ipv4/route.c
> @@ -1366,7 +1366,7 @@ void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more)
> {
> struct rtable *rt = (struct rtable *) dst;
>
> - if (rt) {
> + if (rt&& !(rt->dst.flags& DST_NOPEER)) {
> if (rt->peer == NULL)
> rt_bind_peer(rt, rt->rt_dst, 1);
>
> @@ -1377,7 +1377,7 @@ void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more)
> iph->id = htons(inet_getid(rt->peer, more));
> return;
> }
> - } else
> + } else if (!rt)
> printk(KERN_DEBUG "rt_bind_peer(0) @%p\n",
> __builtin_return_address(0));
>
> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
> index 84d0bd5..ec56271 100644
> --- a/net/ipv6/ip6_output.c
> +++ b/net/ipv6/ip6_output.c
> @@ -603,7 +603,7 @@ void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
> static atomic_t ipv6_fragmentation_id;
> int old, new;
>
> - if (rt) {
> + if (rt&& !(rt->dst.flags& DST_NOPEER)) {
> struct inet_peer *peer;
>
> if (!rt->rt6i_peer)
>
>
Eric,
I'm seeing a new problem now with IPv6 on my bridge, I don't know if
it's related to any of the patches you gave me.
Basically, I have eth0 and eth1 in a balance-rr bond (bond0), and this
is added as a port in a bridge. When the bond and bridge are freshly
brought up, IPv4 works fine but it appears to be deaf to IPv6 traffic.
It stays this way until I run 'tcpdump -i eth0' and 'tcpdump -i eth1'.
If I run tcpdump with the -p flag to not enable promiscuous mode, the
interfaces remain deaf. Only if they enter promiscuous mode do they
start to listen to each other. It also doesn't help to run tcpdump
against bond0 or br0 at all.
I'm not sure if once I've killed tcpdump they become deaf again, but I
have enough IPv6 traffic to keep the neighbour entry alive.
Cheers,
Chris
--
Chris Boot
bootc@bootc.net
^ permalink raw reply
* 3.0.12 - unregister_pernet_gen_subsys hogging whole system
From: Nikola Ciprich @ 2011-12-22 15:19 UTC (permalink / raw)
To: linux-kernel mlist; +Cc: stable, netdev
[-- Attachment #1: Type: text/plain, Size: 1186 bytes --]
Hi,
after updating one of our servers to 3.0.12 kernel, it became painfully slow (actually
it's almost unusable).
trying perf top, I see following:
27465.00 - 59.8% : unregister_pernet_gen_subsys
3144.00 - 6.8% : __start_notes
1211.00 - 2.6% : swiotlb_sync_sg
1155.00 - 2.5% : swiotlb_unmap_sg_attrs
621.00 - 1.4% : pci_pm_init
565.00 - 1.2% : swiotlb_map_sg_attrs
503.00 - 1.1% : cgroup_attach_task
I wasn't too successfull trying to find something related, so I'd like to ask,
which subsystem might be calling unregister_pernet_gen_subsys and why?
I guess this is certaingly a bug... Could somebody please have a look at this?
I'll provide all debugging information I can if needed..
thanks a lot in advance
with best regards
nik
--
-------------------------------------
Ing. Nikola CIPRICH
LinuxBox.cz, s.r.o.
28. rijna 168, 709 01 Ostrava
tel.: +420 596 603 142
fax: +420 596 621 273
mobil: +420 777 093 799
www.linuxbox.cz
mobil servis: +420 737 238 656
email servis: servis@linuxbox.cz
-------------------------------------
[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: [PATCH, v2] Xen: consolidate and simplify struct xenbus_driver instantiation
From: Ben Hutchings @ 2011-12-22 14:44 UTC (permalink / raw)
To: Ian Campbell
Cc: Jan Beulich, Konrad Rzeszutek Wilk, davem@davemloft.net,
dmitry.torokhov@gmail.com, FlorianSchandinat@gmx.de,
Jeremy Fitzhardinge, Jens Axboe, xen-devel@lists.xensource.com,
Konrad Rzeszutek Wilk, linux-kernel@vger.kernel.org,
netdev@vger.kernel.org
In-Reply-To: <1324555060.7877.84.camel@zakaz.uk.xensource.com>
On Thu, 2011-12-22 at 11:57 +0000, Ian Campbell wrote:
> On Thu, 2011-12-22 at 11:51 +0000, Jan Beulich wrote:
> > >>> On 22.12.11 at 10:57, Ian Campbell <Ian.Campbell@citrix.com> wrote:
> > > On Thu, 2011-12-22 at 09:08 +0000, Jan Beulich wrote:
> > >> The 'name', 'owner', and 'mod_name' members are redundant with the
> > >> identically named fields in the 'driver' sub-structure. Rather than
> > >> switching each instance to specify these fields explicitly, introduce
> > >> a macro to simplify this.
> > >>
> > >> Eliminate further redundancy by allowing the drvname argument to
> > >> DEFINE_XENBUS_DRIVER() to be blank (in which case the first entry from
> > >> the ID table will be used for .driver.name).
> > >
> > > Any reason not to always use DRV_NAME here (which is generally a bit
> > > more specific e.g. "xen-foofront" rather than "foo") and rely on the id
> > > table for the shorter names used in xenstore?
> >
> > That would imply that DRV_NAME is always defined, but I don't
> > see this being the case.
>
> My mistake, I thought it was a Kbuild thing.
You're maybe thinking of KBUILD_MODNAME.
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: Invalid Argument when adding a bond to a bridge
From: David Lamparter @ 2011-12-22 14:35 UTC (permalink / raw)
To: Dyweni - NetDev; +Cc: NetDev, Bridge, Bonding Devel
In-Reply-To: <b8003b95089e177b00bc7db44700757a@pl1.haspere.com>
Add an interface to the bond, then add the bond to the bridge.
bond without interface = 00:00:00:00:00:00 MAC = invalid.
On Thu, Dec 22, 2011 at 08:25:54AM -0600, Dyweni - NetDev wrote:
> I created the bond with: echo "+x" > /sys/class/net/bonding_masters
>
> I created the bridge with: brctl addbr b
>
> I try to add the bond to the bridge with: brctl addif b x
^ permalink raw reply
* Invalid Argument when adding a bond to a bridge
From: Dyweni - NetDev @ 2011-12-22 14:25 UTC (permalink / raw)
To: NetDev, Bridge, Bonding Devel
Hi All,
I need some help figuring this one out... Whenever I try to add a bond
to a
bridge, I get back an invalid argument error. I've confirmed this on
3.2-rc6, 3.1.5, 3.0.13, and 2.6.39.4 (haven't checked earlier kernels).
Here's my setup: 32bit KVM virtual machine with no network cards (...
-net
none ... ).
I created the bond with: echo "+x" > /sys/class/net/bonding_masters
I created the bridge with: brctl addbr b
I try to add the bond to the bridge with: brctl addif b x
--
Thanks,
Dyweni
^ permalink raw reply
* Re: BUG: unable to handle kernel NULL pointer dereference in ipv6_select_ident
From: Eric Dumazet @ 2011-12-22 14:15 UTC (permalink / raw)
To: Chris Boot, David Miller; +Cc: lkml, netdev, Steffen Klassert
In-Reply-To: <4EF300B2.3050903@bootc.net>
Le jeudi 22 décembre 2011 à 10:04 +0000, Chris Boot a écrit :
> Eric,
>
> So far so good. I've had this running for several hours this morning
> with more of the prodding that would normally have crashed it, both IPv4
> and IPv6, and it's holding up well.
>
Thanks for testing.
Here is the official patch then (the .mtu() bit belongs to a separate
patch)
[PATCH] net: introduce DST_NOPEER dst flag
Chris Boot reported crashes occurring in ipv6_select_ident().
[ 461.457562] RIP: 0010:[<ffffffff812dde61>] [<ffffffff812dde61>]
ipv6_select_ident+0x31/0xa7
[ 461.578229] Call Trace:
[ 461.580742] <IRQ>
[ 461.582870] [<ffffffff812efa7f>] ? udp6_ufo_fragment+0x124/0x1a2
[ 461.589054] [<ffffffff812dbfe0>] ? ipv6_gso_segment+0xc0/0x155
[ 461.595140] [<ffffffff812700c6>] ? skb_gso_segment+0x208/0x28b
[ 461.601198] [<ffffffffa03f236b>] ? ipv6_confirm+0x146/0x15e
[nf_conntrack_ipv6]
[ 461.608786] [<ffffffff81291c4d>] ? nf_iterate+0x41/0x77
[ 461.614227] [<ffffffff81271d64>] ? dev_hard_start_xmit+0x357/0x543
[ 461.620659] [<ffffffff81291cf6>] ? nf_hook_slow+0x73/0x111
[ 461.626440] [<ffffffffa0379745>] ? br_parse_ip_options+0x19a/0x19a
[bridge]
[ 461.633581] [<ffffffff812722ff>] ? dev_queue_xmit+0x3af/0x459
[ 461.639577] [<ffffffffa03747d2>] ? br_dev_queue_push_xmit+0x72/0x76
[bridge]
[ 461.646887] [<ffffffffa03791e3>] ? br_nf_post_routing+0x17d/0x18f
[bridge]
[ 461.653997] [<ffffffff81291c4d>] ? nf_iterate+0x41/0x77
[ 461.659473] [<ffffffffa0374760>] ? br_flood+0xfa/0xfa [bridge]
[ 461.665485] [<ffffffff81291cf6>] ? nf_hook_slow+0x73/0x111
[ 461.671234] [<ffffffffa0374760>] ? br_flood+0xfa/0xfa [bridge]
[ 461.677299] [<ffffffffa0379215>] ?
nf_bridge_update_protocol+0x20/0x20 [bridge]
[ 461.684891] [<ffffffffa03bb0e5>] ? nf_ct_zone+0xa/0x17 [nf_conntrack]
[ 461.691520] [<ffffffffa0374760>] ? br_flood+0xfa/0xfa [bridge]
[ 461.697572] [<ffffffffa0374812>] ? NF_HOOK.constprop.8+0x3c/0x56
[bridge]
[ 461.704616] [<ffffffffa0379031>] ?
nf_bridge_push_encap_header+0x1c/0x26 [bridge]
[ 461.712329] [<ffffffffa037929f>] ? br_nf_forward_finish+0x8a/0x95
[bridge]
[ 461.719490] [<ffffffffa037900a>] ?
nf_bridge_pull_encap_header+0x1c/0x27 [bridge]
[ 461.727223] [<ffffffffa0379974>] ? br_nf_forward_ip+0x1c0/0x1d4 [bridge]
[ 461.734292] [<ffffffff81291c4d>] ? nf_iterate+0x41/0x77
[ 461.739758] [<ffffffffa03748cc>] ? __br_deliver+0xa0/0xa0 [bridge]
[ 461.746203] [<ffffffff81291cf6>] ? nf_hook_slow+0x73/0x111
[ 461.751950] [<ffffffffa03748cc>] ? __br_deliver+0xa0/0xa0 [bridge]
[ 461.758378] [<ffffffffa037533a>] ? NF_HOOK.constprop.4+0x56/0x56
[bridge]
This is caused by bridge netfilter special dst_entry (fake_rtable), a
special shared entry, where attaching an inetpeer makes no sense.
Problem is present since commit 87c48fa3b46 (ipv6: make fragment
identifications less predictable)
Introduce DST_NOPEER dst flag and make sure ipv6_select_ident() and
__ip_select_ident() fallback to the 'no peer attached' handling.
Reported-by: Chris Boot <bootc@bootc.net>
Tested-by: Chris Boot <bootc@bootc.net>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
include/net/dst.h | 1 +
net/bridge/br_netfilter.c | 2 +-
net/ipv4/route.c | 4 ++--
net/ipv6/ip6_output.c | 2 +-
4 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/include/net/dst.h b/include/net/dst.h
index 6faec1a..75766b4 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -53,6 +53,7 @@ struct dst_entry {
#define DST_NOHASH 0x0008
#define DST_NOCACHE 0x0010
#define DST_NOCOUNT 0x0020
+#define DST_NOPEER 0x0040
short error;
short obsolete;
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index d6ec372..5693e5f 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -141,7 +141,7 @@ void br_netfilter_rtable_init(struct net_bridge *br)
rt->dst.dev = br->dev;
rt->dst.path = &rt->dst;
dst_init_metrics(&rt->dst, br_dst_default_metrics, true);
- rt->dst.flags = DST_NOXFRM;
+ rt->dst.flags = DST_NOXFRM | DST_NOPEER;
rt->dst.ops = &fake_dst_ops;
}
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 252c512..a5004f1 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1366,7 +1366,7 @@ void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more)
{
struct rtable *rt = (struct rtable *) dst;
- if (rt) {
+ if (rt && !(rt->dst.flags & DST_NOPEER)) {
if (rt->peer == NULL)
rt_bind_peer(rt, rt->rt_dst, 1);
@@ -1377,7 +1377,7 @@ void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more)
iph->id = htons(inet_getid(rt->peer, more));
return;
}
- } else
+ } else if (!rt)
printk(KERN_DEBUG "rt_bind_peer(0) @%p\n",
__builtin_return_address(0));
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 84d0bd5..ec56271 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -603,7 +603,7 @@ void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
static atomic_t ipv6_fragmentation_id;
int old, new;
- if (rt) {
+ if (rt && !(rt->dst.flags & DST_NOPEER)) {
struct inet_peer *peer;
if (!rt->rt6i_peer)
^ permalink raw reply related
* Invalid Argument when adding a bond to a bridge
From: Dyweni - NetDev @ 2011-12-22 14:08 UTC (permalink / raw)
To: NetDev, Bridge, Bonding Devel
[-- Attachment #1.1: Type: text/plain, Size: 517 bytes --]
Hi All,
I need some help figuring this one out... Whenever I try
to add a bond to a bridge, I get back an invalid argument error. I've
confirmed this on 3.2-rc6, 3.1.5, 3.0.13, and 2.6.39.4 (haven't checked
earlier kernels).
Here's my setup: 32bit KVM virtual machine with no
network cards (... -net none ... ).
I created the bond with: echo "+x"
> /sys/class/net/bonding_masters
I created the bridge with: brctl
addbr b
I try to add the bond to the bridge with: brctl addif b x
--
Thanks,
Dyweni
[-- Attachment #1.2: Type: text/html, Size: 757 bytes --]
[-- Attachment #2: Type: text/plain, Size: 159 bytes --]
_______________________________________________
Bridge mailing list
Bridge@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/bridge
^ permalink raw reply
* Re: [PATCH v4] ARM: net: JIT compiler for packet filters
From: Eric Dumazet @ 2011-12-22 13:43 UTC (permalink / raw)
To: Mircea Gherzan; +Cc: linux-arm-kernel, netdev, linux
In-Reply-To: <1324558747-15325-1-git-send-email-mgherzan@gmail.com>
Le jeudi 22 décembre 2011 à 13:59 +0100, Mircea Gherzan a écrit :
> Based of Matt Evans's PPC64 implementation.
>
> The compiler generates ARM instructions but interworking is
> supported for Thumb2 kernels.
>
> Supports both little and big endian. Unaligned loads are emitted
> for ARMv6+. Not all the BPF opcodes that deal with ancillary data
> are supported. The scratch memory of the filter lives on the stack.
> Hardware integer division is used if it is available.
>
> Enabled in the same way as for x86-64 and PPC64:
>
> echo 1 > /proc/sys/net/core/bpf_jit_enable
>
> A value greater than 1 enables opcode output.
>
> Signed-off-by: Mircea Gherzan <mgherzan@gmail.com>
> ---
...
> +/*
> + * ABI:
> + *
> + * r0 scratch register
> + * r4 BPF register A
> + * r5 BPF register X
> + * r6 pointer to the skb
> + * r7 skb->data
> + * r8 skb_headlen(skb)
> + */
> +
> +#define r_scratch ARM_R0
> +/* r1-r3 are (also) used for the unaligned loads on the non-ARMv7 slowpath */
> +#define r_off ARM_R1
> +#define r_A ARM_R4
> +#define r_X ARM_R5
> +#define r_skb ARM_R6
> +#define r_skb_data ARM_R7
> +#define r_skb_hl ARM_R8
> +
> +#define SCRATCH_SP_OFFSET 0
> +#define SCRATCH_OFF(k) (SCRATCH_SP_OFFSET + (k))
> +
> +#define SEEN_MEM ((1 << BPF_MEMWORDS) - 1)
> +#define SEEN_MEM_WORD(k) (1 << (k))
> +#define SEEN_X (1 << BPF_MEMWORDS)
> +#define SEEN_CALL (1 << (BPF_MEMWORDS + 1))
> +#define SEEN_DATA (1 << (BPF_MEMWORDS + 2))
> +#define SEEN_LEN (1 << (BPF_MEMWORDS + 3))
This seems wrong. skb->len has nothing special, its a particular case of
skb dereferencing.
You should rename this to SEEN_SKB_REF, and use it for everything
needing r_skb :
> + if (ctx->seen & (SEEN_DATA | SEEN_LEN))
> + emit(ARM_MOV_R(r_skb, ARM_R0), ctx);
> +
here you handled the thing correctly.
> + case BPF_S_LD_W_LEN:
> + ctx->seen |= SEEN_LEN;
> + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
> + emit(ARM_LDR_I(r_A, r_skb,
> + offsetof(struct sk_buff, len)), ctx);
> + break;
but here there is a problem :
> + case BPF_S_ANC_PROTOCOL:
> + /* A = ntohs(skb->protocol) */
> + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
> + protocol) != 2);
> + off = offsetof(struct sk_buff, protocol);
> + emit(ARM_LDRH_I(r_scratch, r_skb, off), ctx);
> + emit_swap16(r_A, r_scratch, ctx);
> + break;
here too :
> + case BPF_S_ANC_IFINDEX:
> + /* A = skb->dev->ifindex */
> + off = offsetof(struct sk_buff, dev);
> + emit(ARM_LDR_I(r_scratch, r_skb, off), ctx);
> +
> + emit(ARM_CMP_I(r_scratch, 0), ctx);
> + emit_err_ret(ARM_COND_EQ, ctx);
> +
> + BUILD_BUG_ON(FIELD_SIZEOF(struct net_device,
> + ifindex) != 4);
> + off = offsetof(struct net_device, ifindex);
> + emit(ARM_LDR_I(r_A, r_scratch, off), ctx);
> + break;
here too :
> + case BPF_S_ANC_MARK:
> + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
> + off = offsetof(struct sk_buff, mark);
> + emit(ARM_LDR_I(r_A, r_skb, off), ctx);
> + break;
here too :
> + case BPF_S_ANC_RXHASH:
> + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
> + off = offsetof(struct sk_buff, rxhash);
> + emit(ARM_LDR_I(r_A, r_skb, off), ctx);
> + break;
and also here :
> + case BPF_S_ANC_QUEUE:
> + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
> + queue_mapping) != 2);
> + BUILD_BUG_ON(offsetof(struct sk_buff,
> + queue_mapping) > 0xff);
> + off = offsetof(struct sk_buff, queue_mapping);
> + emit(ARM_LDRH_I(r_A, r_skb, off), ctx);
> + break;
^ permalink raw reply
* Re: ICMP packets - ll_temac with Microblaze
From: Michael Wang @ 2011-12-22 13:42 UTC (permalink / raw)
To: Eric Dumazet; +Cc: monstr, David Miller, John Williams, netdev
In-Reply-To: <1324560068.2153.6.camel@edumazet-HP-Compaq-6005-Pro-SFF-PC>
On 12/22/2011 09:21 PM, Eric Dumazet wrote:
> Le jeudi 22 décembre 2011 à 21:01 +0800, Michael Wang a écrit :
>
>> Hi, Eric
>>
>> So do you mean the way is:
>>
>> ip_local_deliver_finish --> raw_local_deliver --> raw_v4_input -->
>> raw_rcv --> raw_rcv_skb --> sock_queue_rcv_skb
>>
>> And in sock_queue_rcv_skb:
>>
>> if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
>> (unsigned)sk->sk_rcvbuf) {
>> atomic_inc(&sk->sk_drops);
>> trace_sock_rcvqueue_full(sk, skb);
>> return -ENOMEM; //drop?
>> }
>>
>> Is this the way the packet being dropped? Is this confirmed by some printk?
>>
>> Sorry if the question is naive, I just want to make sure I am checking
>> at the right place.
>>
>
> Yep
>
> Are you aware I already posted a patch to solve the problem ?
>
> http://patchwork.ozlabs.org/patch/132698/
>
Oh, sorry, I don't know about that, congratulation :)
Regards,
Michael Wang
>
>
^ permalink raw reply
* Re: ICMP packets - ll_temac with Microblaze
From: Eric Dumazet @ 2011-12-22 13:21 UTC (permalink / raw)
To: Michael Wang; +Cc: monstr, David Miller, John Williams, netdev
In-Reply-To: <4EF32A21.3060503@linux.vnet.ibm.com>
Le jeudi 22 décembre 2011 à 21:01 +0800, Michael Wang a écrit :
> Hi, Eric
>
> So do you mean the way is:
>
> ip_local_deliver_finish --> raw_local_deliver --> raw_v4_input -->
> raw_rcv --> raw_rcv_skb --> sock_queue_rcv_skb
>
> And in sock_queue_rcv_skb:
>
> if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
> (unsigned)sk->sk_rcvbuf) {
> atomic_inc(&sk->sk_drops);
> trace_sock_rcvqueue_full(sk, skb);
> return -ENOMEM; //drop?
> }
>
> Is this the way the packet being dropped? Is this confirmed by some printk?
>
> Sorry if the question is naive, I just want to make sure I am checking
> at the right place.
>
Yep
Are you aware I already posted a patch to solve the problem ?
http://patchwork.ozlabs.org/patch/132698/
^ permalink raw reply
* Re: [PATCH net-next v2 2/4] can: cc770: add legacy ISA bus driver for the CC770 and AN82527
From: Wolfgang Zarre @ 2011-12-22 13:20 UTC (permalink / raw)
To: Wolfgang Grandegger
Cc: Oliver Hartkopp, linux-can-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA,
socketcan-users-0fE9KPoRgkgATYTw5x5z8w
In-Reply-To: <4EF2FA3F.3010308-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
Hello Wolfgang,
> Hi Wolfgang,
>
> On 12/21/2011 07:32 PM, Wolfgang Zarre wrote:
>> Hello Wolfgang,
> ...
>
>>> It's a bug! netif_start_queue is missing at the end of the open
>>> function. Got lost some how. I have just updated (rebased!) my
>>> wg-linux-can-next repository.
>>
>> Ok, I was checking out last week and since I'm running one test series
>> after the other.
>>
>> There are several odd issues I could found and I'm trying to trace them
>> down beside some other work.
>>
>> Even with an assumed correct configuration like I was using with the lincan
>> driver I'm loosing telegrams so around 1 till 2 in 500000 but might be a
>> different sample-point at the PLC which is opaque due the predefined
>> setting.
>
> In principle, messages can be lost because the cc770 does buffer only up
> to two messages in hardware. If they are not read out quickly enough,
> message loss will happen. The CAN statistics should list such overruns,
> though.
>
Actually I loose them on transmission, not reception, but as mentioned
one time we traced with a second PC and there the telegrams are not lost
which means they are really going over the bus physically.
So maybe just a timing issue but for now secondary.
However the telegrams are sent with 5ms space parallel to the heartbeat.
>> For the next test I'll set the BTR's directly.
>
> OK, if you do not see bus errors, everything should be fine.
>
The test with BTR's set was not working out due the fact that
the software for coding the PLC doesn't allow, I'm loving it.
>> Further sometimes I can find one in dropped but mostly not.
>>
>> But more odd is that after an undefined time the transmission gets
>> stuck followed by a buffer overrun but can receive.
>
> I recently found a bug. Please try this fix:
>
> http://marc.info/?l=linux-can&m=132370253713701&w=4
The fix is already included as checked out.
>
> Did you realize related error messages in the dmesg output?
Nothing at all, as mentioned .
>
>> No error messages nor changes in ip -d -s link show can0.
>>
>> Additional it seems that neither the automatic restart nor
>> the manual one works.
>
> What version are you using. I think this problem has been fixed by
> adding the missing netif_start_queue() at the end of the open
> function, as mentioned above. Do you have that in your driver?
>
Yes, is already included as well, I'm using commit
eec921ac28fde243456078a557768808d93d94a3
>> ip link set can0 up type can restart gives me 'RTNETLINK answers: Invalid
>> argument' and ip link set can0 up type can bitrate 500000 restart a
>> RTNETLINK answers: Device or resource busy but nothing connected to can0.
>
> The error message is shown because you try to set bitrate when the
> device is up. For the restart after bus-off just type:
>
> # ip link set can0 type can restart
Actually I tried it when it's get stuck but is anyway a hint that
the device is still up,
>
> Anyway, if you run into a bus-off, then it's likely that you have
> electrical problems on the CAN bus, e.g. termination, mismatching
> bit-timing parameters.
As said I have no indication of any kind of problem:
5: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UNKNOWN qlen 10
link/can
can state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 2000
bitrate 500000 sample-point 0.750
tq 125 prop-seg 5 phase-seg1 6 phase-seg2 4 sjw 1
cc770: tseg1 1..16 tseg2 1..8 sjw 1..4 brp 1..64 brp-inc 1
clock 16000000
re-started bus-errors arbit-lost error-warn error-pass bus-off
0 0 0 0 0 0
RX: bytes packets errors dropped overrun mcast
76506 74616 0 0 0 0
TX: bytes packets errors dropped carrier collsns
2450703 616355 0 0 0 0
>
>> So I have to perform per example ip link set can0 down;ip link set can0 up
>> type can bitrate 500000 restart-ms 2000 sample-point 0.75
>> but this is emptying the buffer and these telegrams are lost then as well.
>>
>> I was comparing with my lincan driver which was running so far ok also
>> to confirm a proper working PLC.
>>
>> First I assumed that maybe the set_reset_mode procedure is responsible for
>> that misbehaviour because according to the cc770 manual we should wait for
>> a zero of bit 7 RstST of the CPU interface register but when the
>> transmission
>> gets stuck there was no call for set_reset_mode.
>>
>> Maybe it's ending up somehow recessive.
>>
>> Anyway, I might compare the registers of both drivers just to figure out
>> what's going on but maybe You have an idea as well.
>>
>> Problem is just it runs always quite some time until the issues happen
>> otherwise it would be more easy.
>
> Again, please check if you have netif_start_queue() at the end of the
> open function.
>
As said I'm using eec921ac28fde243456078a557768808d93d94a3
However, I'll try further to investigate that issue due the fact having it
running with my lincan without problems and therefore it should be possible
to find the problem.
> Wolfgang.
Wolfgang
^ permalink raw reply
* Re: BCM43224 hanging [3.2.0-rc5]
From: Arend van Spriel @ 2011-12-22 13:19 UTC (permalink / raw)
To: Nico Schottelius, LKML, netdev, b43-dev, Greg KH
In-Reply-To: <20111222102408.GA2643@schottelius.org>
On 12/22/2011 11:24 AM, Nico Schottelius wrote:
> Update:
>
> - dmesg with hanging logs
> - The hang problem seems to happen ONLY with a specific access point: c8:6c:87:a9:df:a9
> -> this is a zyxel P-2802HWL-I1, running at channel 13, with WPA2-PSK.
> -> If you need more information, just let me know
> - Using wlan with the Samsung S2 as access point seems to work fine
Is the Samsung AP also on channel 13? If not, could you try it?
> So this is now a rather specific issue, but I guess others will run into
> this sooner or later as well.
>
> Attached dmesg with hanging processes including traceback.
>
> Nico
>
Gr. AvS
^ permalink raw reply
* Re: ICMP packets - ll_temac with Microblaze
From: Michael Wang @ 2011-12-22 13:01 UTC (permalink / raw)
To: Eric Dumazet; +Cc: monstr, David Miller, John Williams, netdev
In-Reply-To: <1324550811.2153.3.camel@edumazet-HP-Compaq-6005-Pro-SFF-PC>
On 12/22/2011 06:46 PM, Eric Dumazet wrote:
> Le jeudi 22 décembre 2011 à 18:32 +0800, Michael Wang a écrit :
>> On 12/21/2011 06:11 PM, Michal Simek wrote:
>>
>>> Hi Eric and David,
>>>
>>> I have found one problem with ll_temac driver and
>>> this commit: net: more accurate skb truesize
>>> sha1: 87fb4b7b533073eeeaed0b6bf7c2328995f6c075
>>>
>>> The problem is only with icmp packets from the target. It is sent and
>>> driver receive it
>>> but it is not proceed to the application.
>>>
>>
>> Hi, Michal
>>
>> What's the type of icmp you are using? such as "EchoReps", we can find
>> the actually handler routine by this type.
>>
>> And you said the packet already received by driver, can you tell me the
>> way you used to confirm this?
>>
>> And have you checked when was the icmp packet being dropped, is it in
>> icmp_rcv or before or later?
>
> Packet was dropped right before being queued in RAW socket
> receive_queue, because of low sk_rcvbuf setting (against skb->truesize)
>
Hi, Eric
So do you mean the way is:
ip_local_deliver_finish --> raw_local_deliver --> raw_v4_input -->
raw_rcv --> raw_rcv_skb --> sock_queue_rcv_skb
And in sock_queue_rcv_skb:
if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
(unsigned)sk->sk_rcvbuf) {
atomic_inc(&sk->sk_drops);
trace_sock_rcvqueue_full(sk, skb);
return -ENOMEM; //drop?
}
Is this the way the packet being dropped? Is this confirmed by some printk?
Sorry if the question is naive, I just want to make sure I am checking
at the right place.
Regards,
Michael Wang
>
>
^ permalink raw reply
* [PATCH v4] ARM: net: JIT compiler for packet filters
From: Mircea Gherzan @ 2011-12-22 12:59 UTC (permalink / raw)
To: linux-arm-kernel; +Cc: mgherzan, netdev, linux
Based of Matt Evans's PPC64 implementation.
The compiler generates ARM instructions but interworking is
supported for Thumb2 kernels.
Supports both little and big endian. Unaligned loads are emitted
for ARMv6+. Not all the BPF opcodes that deal with ancillary data
are supported. The scratch memory of the filter lives on the stack.
Hardware integer division is used if it is available.
Enabled in the same way as for x86-64 and PPC64:
echo 1 > /proc/sys/net/core/bpf_jit_enable
A value greater than 1 enables opcode output.
Signed-off-by: Mircea Gherzan <mgherzan@gmail.com>
---
Changes in v4:
* first check if the JIT compiler is enabled
* fix the code generation for the LDX_MSH opcode
Changes in v3:
* no longer depend on EABI and !Thumb2
* add BLX "emulation" for ARMv4 without Thumb
* use the integer divide instruction on Cortex-A15
* fix the handling of the DIV_K opcode
* use a C wrapper for __aeabi_uidiv
* fix the generation of the epilogue (non-FP case)
Changes in v2:
* enable the compiler ony for ARMv5+ because of the BLX instruction
* use the same comparison for the ARM version checks
* use misaligned accesses on ARMv6
* fix the SEEN_MEM
* fix the mem_words_used()
arch/arm/Kconfig | 1 +
arch/arm/Makefile | 1 +
arch/arm/net/Makefile | 3 +
arch/arm/net/bpf_jit_32.c | 883 +++++++++++++++++++++++++++++++++++++++++++++
arch/arm/net/bpf_jit_32.h | 180 +++++++++
5 files changed, 1068 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/net/Makefile
create mode 100644 arch/arm/net/bpf_jit_32.c
create mode 100644 arch/arm/net/bpf_jit_32.h
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index abba5b8..0014b4b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -30,6 +30,7 @@ config ARM
select HAVE_SPARSE_IRQ
select GENERIC_IRQ_SHOW
select CPU_PM if (SUSPEND || CPU_IDLE)
+ select HAVE_BPF_JIT
help
The ARM series is a line of low-power-consumption RISC chip designs
licensed by ARM Ltd and targeted at embedded applications and
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index dfcf3b0..8810a10 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -255,6 +255,7 @@ core-$(CONFIG_VFP) += arch/arm/vfp/
# If we have a machine-specific directory, then include it in the build.
core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
+core-y += arch/arm/net/
core-y += $(machdirs) $(platdirs)
drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
diff --git a/arch/arm/net/Makefile b/arch/arm/net/Makefile
new file mode 100644
index 0000000..c2c1084
--- /dev/null
+++ b/arch/arm/net/Makefile
@@ -0,0 +1,3 @@
+# ARM-specific networking code
+
+obj-$(CONFIG_BPF_JIT) += bpf_jit_32.o
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
new file mode 100644
index 0000000..d4c02f4
--- /dev/null
+++ b/arch/arm/net/bpf_jit_32.c
@@ -0,0 +1,883 @@
+/*
+ * Just-In-Time compiler for BPF filters on 32bit ARM
+ *
+ * Copyright (c) 2011 Mircea Gherzan <mgherzan@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/bitops.h>
+#include <linux/compiler.h>
+#include <linux/filter.h>
+#include <linux/moduleloader.h>
+#include <linux/netdevice.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <asm/cacheflush.h>
+#include <asm/hwcap.h>
+
+#include "bpf_jit_32.h"
+
+/*
+ * ABI:
+ *
+ * r0 scratch register
+ * r4 BPF register A
+ * r5 BPF register X
+ * r6 pointer to the skb
+ * r7 skb->data
+ * r8 skb_headlen(skb)
+ */
+
+#define r_scratch ARM_R0
+/* r1-r3 are (also) used for the unaligned loads on the non-ARMv7 slowpath */
+#define r_off ARM_R1
+#define r_A ARM_R4
+#define r_X ARM_R5
+#define r_skb ARM_R6
+#define r_skb_data ARM_R7
+#define r_skb_hl ARM_R8
+
+#define SCRATCH_SP_OFFSET 0
+#define SCRATCH_OFF(k) (SCRATCH_SP_OFFSET + (k))
+
+#define SEEN_MEM ((1 << BPF_MEMWORDS) - 1)
+#define SEEN_MEM_WORD(k) (1 << (k))
+#define SEEN_X (1 << BPF_MEMWORDS)
+#define SEEN_CALL (1 << (BPF_MEMWORDS + 1))
+#define SEEN_DATA (1 << (BPF_MEMWORDS + 2))
+#define SEEN_LEN (1 << (BPF_MEMWORDS + 3))
+
+struct jit_ctx {
+ const struct sk_filter *skf;
+ unsigned idx;
+ unsigned prologue_bytes;
+ int ret0_fp_idx;
+ u32 seen;
+ u32 *offsets;
+ u32 *target;
+#if __LINUX_ARM_ARCH__ < 7
+ u16 epilogue_bytes;
+ u16 imm_count;
+ u32 *imms;
+#endif
+};
+
+int bpf_jit_enable __read_mostly;
+
+static u8 jit_get_skb_b(struct sk_buff *skb, unsigned offset)
+{
+ u8 ret;
+ skb_copy_bits(skb, offset, &ret, 1);
+ return ret;
+}
+
+static u16 jit_get_skb_h(struct sk_buff *skb, unsigned offset)
+{
+ u16 ret;
+ skb_copy_bits(skb, offset, &ret, 2);
+ return ntohs(ret);
+}
+
+static u32 jit_get_skb_w(struct sk_buff *skb, unsigned offset)
+{
+ u32 ret;
+ skb_copy_bits(skb, offset, &ret, 4);
+ return ntohl(ret);
+}
+
+/*
+ * Wrapper that handles both OABI and EABI and assures Thumb2 interworking
+ * (where the assembly routines like __aeabi_uidiv could cause problems).
+ */
+static u32 jit_udiv(u32 dividend, u32 divisor)
+{
+ return dividend / divisor;
+}
+
+static inline void _emit(int cond, u32 inst, struct jit_ctx *ctx)
+{
+ if (ctx->target != NULL)
+ ctx->target[ctx->idx] = inst | (cond << 28);
+
+ ctx->idx++;
+}
+
+/*
+ * Emit an instruction that will be executed unconditionally.
+ */
+static inline void emit(u32 inst, struct jit_ctx *ctx)
+{
+ _emit(ARM_COND_AL, inst, ctx);
+}
+
+static u16 saved_regs(struct jit_ctx *ctx)
+{
+ u16 ret = 0;
+
+ if (ctx->skf->len > 1)
+ ret |= 1 << r_A;
+
+#ifdef CONFIG_FRAME_POINTER
+ ret |= (1 << ARM_FP) | (1 << ARM_IP) | (1 << ARM_LR) | (1 << ARM_PC);
+#else
+ if (ctx->seen & SEEN_CALL)
+ ret |= 1 << ARM_LR;
+#endif
+ if (ctx->seen & (SEEN_DATA | SEEN_LEN))
+ ret |= 1 << r_skb;
+ if (ctx->seen & SEEN_DATA)
+ ret |= (1 << r_skb_data) | (1 << r_skb_hl);
+ if (ctx->seen & SEEN_X)
+ ret |= 1 << r_X;
+
+ return ret;
+}
+
+static inline int mem_words_used(struct jit_ctx *ctx)
+{
+ u32 words = ctx->seen & SEEN_MEM;
+ /* yes, we do waste some stack space IF there are "holes" in the set" */
+ return 32 - __builtin_clz(words);
+}
+
+static inline bool is_load_to_a(u16 inst)
+{
+ switch (inst) {
+ case BPF_S_LD_W_LEN:
+ case BPF_S_LD_W_ABS:
+ case BPF_S_LD_H_ABS:
+ case BPF_S_LD_B_ABS:
+ case BPF_S_ANC_CPU:
+ case BPF_S_ANC_IFINDEX:
+ case BPF_S_ANC_MARK:
+ case BPF_S_ANC_PROTOCOL:
+ case BPF_S_ANC_RXHASH:
+ case BPF_S_ANC_QUEUE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void build_prologue(struct jit_ctx *ctx)
+{
+ u16 reg_set = saved_regs(ctx);
+ u16 first_inst = ctx->skf->insns[0].code;
+ u16 off;
+
+#ifdef CONFIG_FRAME_POINTER
+ emit(ARM_MOV_R(ARM_IP, ARM_SP), ctx);
+ emit(ARM_PUSH(reg_set), ctx);
+ emit(ARM_SUB_I(ARM_FP, ARM_IP, 4), ctx);
+#else
+ if (reg_set)
+ emit(ARM_PUSH(reg_set), ctx);
+#endif
+
+ if (ctx->seen & (SEEN_DATA | SEEN_LEN))
+ emit(ARM_MOV_R(r_skb, ARM_R0), ctx);
+
+ if (ctx->seen & SEEN_DATA) {
+ off = offsetof(struct sk_buff, data);
+ emit(ARM_LDR_I(r_skb_data, r_skb, off), ctx);
+ /* headlen = len - data_len */
+ off = offsetof(struct sk_buff, len);
+ emit(ARM_LDR_I(r_skb_hl, r_skb, off), ctx);
+ off = offsetof(struct sk_buff, data_len);
+ emit(ARM_LDR_I(r_scratch, r_skb, off), ctx);
+ emit(ARM_SUB_R(r_skb_hl, r_skb_hl, r_scratch), ctx);
+ }
+
+ if (ctx->seen & SEEN_X)
+ emit(ARM_MOV_I(r_X, 0), ctx);
+
+ /* do not leak kernel data to userspace */
+ if ((first_inst != BPF_S_RET_K) && !(is_load_to_a(first_inst)))
+ emit(ARM_MOV_I(r_A, 0), ctx);
+
+ /* stack space for the BPF_MEM words */
+ if (ctx->seen & SEEN_MEM)
+ emit(ARM_SUB_I(ARM_SP, ARM_SP, mem_words_used(ctx) * 4), ctx);
+}
+
+static void build_epilogue(struct jit_ctx *ctx)
+{
+ u16 reg_set = saved_regs(ctx);
+
+ if (ctx->seen & SEEN_MEM)
+ emit(ARM_ADD_I(ARM_SP, ARM_SP, mem_words_used(ctx) * 4), ctx);
+
+ reg_set &= ~(1 << ARM_LR);
+
+#ifdef CONFIG_FRAME_POINTER
+ /* the first instruction of the prologue was: mov ip, sp */
+ reg_set &= ~(1 << ARM_IP);
+ reg_set |= (1 << ARM_SP);
+ emit(ARM_LDM(ARM_SP, reg_set), ctx);
+#else
+ if (ctx->seen) {
+ if (ctx->seen & SEEN_CALL)
+ reg_set |= 1 << ARM_PC;
+ emit(ARM_POP(reg_set), ctx);
+ }
+
+ if (!(ctx->seen & SEEN_CALL))
+ emit(ARM_BX(ARM_LR), ctx);
+#endif
+}
+
+static int16_t imm8m(u32 x)
+{
+ u32 rot;
+
+ for (rot = 0; rot < 16; rot++)
+ if ((x & ~ror32(0xff, 2 * rot)) == 0)
+ return rol32(x, 2 * rot) | (rot << 8);
+
+ return -1;
+}
+
+#if __LINUX_ARM_ARCH__ < 7
+
+static u16 imm_offset(u32 k, struct jit_ctx *ctx)
+{
+ unsigned i = 0, offset;
+ u16 imm;
+
+ /* on the "fake" run we just count them (duplicates included) */
+ if (ctx->target == NULL) {
+ ctx->imm_count++;
+ return 0;
+ }
+
+ while ((i < ctx->imm_count) && ctx->imms[i]) {
+ if (ctx->imms[i] == k)
+ break;
+ i++;
+ }
+
+ if (ctx->imms[i] == 0)
+ ctx->imms[i] = k;
+
+ /* constants go just after the epilogue */
+ offset = ctx->offsets[ctx->skf->len];
+ offset += ctx->prologue_bytes;
+ offset += ctx->epilogue_bytes;
+ offset += i * 4;
+
+ ctx->target[offset / 4] = k;
+
+ /* PC in ARM mode == address of the instruction + 8 */
+ imm = offset - (8 + ctx->idx * 4);
+
+ return imm;
+}
+
+#endif /* __LINUX_ARM_ARCH__ */
+
+/*
+ * Move an immediate that's not an imm8m to a core register.
+ */
+static inline void emit_mov_i_no8m(int rd, u32 val, struct jit_ctx *ctx)
+{
+#if __LINUX_ARM_ARCH__ < 7
+ emit(ARM_LDR_I(rd, ARM_PC, imm_offset(val, ctx)), ctx);
+#else
+ emit(ARM_MOVW(rd, val & 0xffff), ctx);
+ if (val > 0xffff)
+ emit(ARM_MOVT(rd, val >> 16), ctx);
+#endif
+}
+
+static inline void emit_mov_i(int rd, u32 val, struct jit_ctx *ctx)
+{
+ int imm12 = imm8m(val);
+
+ if (imm12 >= 0)
+ emit(ARM_MOV_I(rd, imm12), ctx);
+ else
+ emit_mov_i_no8m(rd, val, ctx);
+}
+
+#if __LINUX_ARM_ARCH__ < 6
+
+static void emit_load_be32(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx)
+{
+ _emit(cond, ARM_LDRB_I(ARM_R3, r_addr, 1), ctx);
+ _emit(cond, ARM_LDRB_I(ARM_R1, r_addr, 0), ctx);
+ _emit(cond, ARM_LDRB_I(ARM_R2, r_addr, 3), ctx);
+ _emit(cond, ARM_LSL_I(ARM_R3, ARM_R3, 16), ctx);
+ _emit(cond, ARM_LDRB_I(ARM_R0, r_addr, 2), ctx);
+ _emit(cond, ARM_ORR_S(ARM_R3, ARM_R3, ARM_R1, SRTYPE_LSL, 24), ctx);
+ _emit(cond, ARM_ORR_R(ARM_R3, ARM_R3, ARM_R2), ctx);
+ _emit(cond, ARM_ORR_S(r_res, ARM_R3, ARM_R0, SRTYPE_LSL, 8), ctx);
+}
+
+static void emit_load_be16(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx)
+{
+ _emit(cond, ARM_LDRB_I(ARM_R1, r_addr, 0), ctx);
+ _emit(cond, ARM_LDRB_I(ARM_R2, r_addr, 1), ctx);
+ _emit(cond, ARM_ORR_S(r_res, ARM_R2, ARM_R1, SRTYPE_LSL, 8), ctx);
+}
+
+static inline void emit_swap16(u8 r_dst, u8 r_src, struct jit_ctx *ctx)
+{
+ emit(ARM_LSL_R(ARM_R1, r_src, 8), ctx);
+ emit(ARM_ORR_S(r_dst, ARM_R1, r_src, SRTYPE_LSL, 8), ctx);
+ emit(ARM_LSL_I(r_dst, r_dst, 8), ctx);
+ emit(ARM_LSL_R(r_dst, r_dst, 8), ctx);
+}
+
+#else /* ARMv6+ */
+
+static void emit_load_be32(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx)
+{
+ _emit(cond, ARM_LDR_I(r_res, r_addr, 0), ctx);
+#ifdef __LITTLE_ENDIAN
+ _emit(cond, ARM_REV(r_res, r_res), ctx);
+#endif
+}
+
+static void emit_load_be16(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx)
+{
+ _emit(cond, ARM_LDRH_I(r_res, r_addr, 0), ctx);
+#ifdef __LITTLE_ENDIAN
+ _emit(cond, ARM_REV16(r_res, r_res), ctx);
+#endif
+}
+
+static inline void emit_swap16(u8 r_dst __maybe_unused,
+ u8 r_src __maybe_unused,
+ struct jit_ctx *ctx __maybe_unused)
+{
+#ifdef __LITTLE_ENDIAN
+ emit(ARM_REV16(r_dst, r_src), ctx);
+#endif
+}
+
+#endif /* __LINUX_ARM_ARCH__ < 6 */
+
+
+/* Compute the immediate value for a PC-relative branch. */
+static inline u32 b_imm(unsigned tgt, struct jit_ctx *ctx)
+{
+ u32 imm;
+
+ if (ctx->target == NULL)
+ return 0;
+ /*
+ * BPF allows only forward jumps and the offset of the target is
+ * still the one computed during the first pass.
+ */
+ imm = ctx->offsets[tgt] + ctx->prologue_bytes - (ctx->idx * 4 + 8);
+
+ return imm >> 2;
+}
+
+#define OP_IMM3(op, r1, r2, imm_val, ctx) \
+ do { \
+ imm12 = imm8m(imm_val); \
+ if (imm12 < 0) { \
+ emit_mov_i_no8m(r_scratch, imm_val, ctx); \
+ emit(op ## _R((r1), (r2), r_scratch), ctx); \
+ } else { \
+ emit(op ## _I((r1), (r2), imm12), ctx); \
+ } \
+ } while (0)
+
+static inline void emit_err_ret(u8 cond, struct jit_ctx *ctx)
+{
+ if (ctx->ret0_fp_idx >= 0) {
+ _emit(cond, ARM_B(b_imm(ctx->ret0_fp_idx, ctx)), ctx);
+ /* NOP to keep the size constant between passes */
+ emit(ARM_MOV_R(ARM_R0, ARM_R0), ctx);
+ } else {
+ _emit(cond, ARM_MOV_I(ARM_R0, 0), ctx);
+ _emit(cond, ARM_B(b_imm(ctx->skf->len, ctx)), ctx);
+ }
+}
+
+static inline void emit_blx_r(u8 tgt_reg, struct jit_ctx *ctx)
+{
+#if __LINUX_ARM_ARCH__ < 5
+ emit(ARM_MOV_R(ARM_LR, ARM_PC), ctx);
+
+ if (elf_hwcap & HWCAP_THUMB)
+ emit(ARM_BX(tgt_reg), ctx);
+ else
+ emit(ARM_MOV_R(ARM_PC, tgt_reg), ctx);
+#else
+ emit(ARM_BLX_R(tgt_reg), ctx);
+#endif
+}
+
+static inline void emit_udiv(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx)
+{
+#if __LINUX_ARM_ARCH__ == 7
+ if (elf_hwcap & HWCAP_IDIVA) {
+ emit(ARM_UDIV(rd, rm, rn), ctx);
+ return;
+ }
+#endif
+ if (rm != ARM_R0)
+ emit(ARM_MOV_R(ARM_R0, rm), ctx);
+ if (rn != ARM_R1)
+ emit(ARM_MOV_R(ARM_R1, rn), ctx);
+
+ ctx->seen |= SEEN_CALL;
+ emit_mov_i(ARM_R3, (u32)jit_udiv, ctx);
+ emit_blx_r(ARM_R3, ctx);
+
+ if (rd != ARM_R0)
+ emit(ARM_MOV_R(rd, ARM_R0), ctx);
+}
+
+static int build_body(struct jit_ctx *ctx)
+{
+ void *load_func[] = {jit_get_skb_b, jit_get_skb_h, jit_get_skb_w};
+ const struct sk_filter *prog = ctx->skf;
+ const struct sock_filter *inst;
+ unsigned i, load_order, off, condt, condf;
+ int imm12;
+ u32 k;
+
+ for (i = 0; i < prog->len; i++) {
+ inst = &(prog->insns[i]);
+ /* K as an immediate value operand */
+ k = inst->k;
+
+ /* compute offsets only in the fake pass */
+ if (ctx->target == NULL)
+ ctx->offsets[i] = ctx->idx * 4;
+
+ switch (inst->code) {
+ case BPF_S_LD_IMM:
+ emit_mov_i(r_A, k, ctx);
+ break;
+ case BPF_S_LD_W_LEN:
+ ctx->seen |= SEEN_LEN;
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
+ emit(ARM_LDR_I(r_A, r_skb,
+ offsetof(struct sk_buff, len)), ctx);
+ break;
+ case BPF_S_LD_MEM:
+ /* A = scratch[k] */
+ ctx->seen |= SEEN_MEM_WORD(k);
+ emit(ARM_LDR_I(r_A, ARM_SP, SCRATCH_OFF(k)), ctx);
+ break;
+ case BPF_S_LD_W_ABS:
+ load_order = 2;
+ goto load;
+ case BPF_S_LD_H_ABS:
+ load_order = 1;
+ goto load;
+ case BPF_S_LD_B_ABS:
+ load_order = 0;
+load:
+ emit_mov_i(r_off, k, ctx);
+load_common:
+ ctx->seen |= SEEN_DATA | SEEN_CALL;
+
+ if (load_order > 0) {
+ emit(ARM_SUB_I(r_scratch, r_skb_hl,
+ 1 << load_order), ctx);
+ emit(ARM_CMP_R(r_scratch, r_off), ctx);
+ condt = ARM_COND_HS;
+ } else {
+ emit(ARM_CMP_R(r_skb_hl, r_off), ctx);
+ condt = ARM_COND_HI;
+ }
+
+ _emit(condt, ARM_ADD_R(r_scratch, r_off, r_skb_data),
+ ctx);
+
+ if (load_order == 0)
+ _emit(condt, ARM_LDRB_I(r_A, r_scratch, 0),
+ ctx);
+ else if (load_order == 1)
+ emit_load_be16(condt, r_A, r_scratch, ctx);
+ else if (load_order == 2)
+ emit_load_be32(condt, r_A, r_scratch, ctx);
+
+ _emit(condt, ARM_B(b_imm(i + 1, ctx)), ctx);
+
+ /* the slowpath */
+ emit_mov_i(ARM_R3, (u32)load_func[load_order], ctx);
+ emit(ARM_MOV_R(ARM_R0, r_skb), ctx);
+ /* the offset is already in R1 */
+ emit_blx_r(ARM_R3, ctx);
+ emit(ARM_MOV_R(r_A, ARM_R0), ctx);
+ break;
+ case BPF_S_LD_W_IND:
+ load_order = 2;
+ goto load_ind;
+ case BPF_S_LD_H_IND:
+ load_order = 1;
+ goto load_ind;
+ case BPF_S_LD_B_IND:
+ load_order = 0;
+load_ind:
+ OP_IMM3(ARM_ADD, r_off, r_X, k, ctx);
+ goto load_common;
+ case BPF_S_LDX_IMM:
+ ctx->seen |= SEEN_X;
+ emit_mov_i(r_X, k, ctx);
+ break;
+ case BPF_S_LDX_W_LEN:
+ ctx->seen |= SEEN_X;
+ emit(ARM_LDR_I(r_X, r_skb,
+ offsetof(struct sk_buff, len)), ctx);
+ break;
+ case BPF_S_LDX_MEM:
+ ctx->seen |= SEEN_X | SEEN_MEM_WORD(k);
+ emit(ARM_LDR_I(r_X, ARM_SP, SCRATCH_OFF(k)), ctx);
+ break;
+ case BPF_S_LDX_B_MSH:
+ /* x = ((*(frame + k)) & 0xf) << 2; */
+ ctx->seen |= SEEN_X | SEEN_DATA | SEEN_CALL;
+ /* offset in r1: we might have to take the slow path */
+ emit_mov_i(r_off, k, ctx);
+ emit(ARM_CMP_R(r_skb_hl, r_off), ctx);
+
+ /* load in r0: common with the slowpath */
+ _emit(ARM_COND_HI, ARM_LDRB_R(ARM_R0, r_skb_data,
+ ARM_R1), ctx);
+ /*
+ * emit_mov_i() might generate one or two instructions,
+ * the same holds for emit_blx_r()
+ */
+ _emit(ARM_COND_HI, ARM_B(b_imm(i + 1, ctx) - 2), ctx);
+
+ emit(ARM_MOV_R(ARM_R0, r_skb), ctx);
+ /* r_off is r1 */
+ emit_mov_i(ARM_R3, (u32)jit_get_skb_b, ctx);
+ emit_blx_r(ARM_R3, ctx);
+
+ emit(ARM_ORR_I(r_X, ARM_R0, 0x00f), ctx);
+ emit(ARM_LSL_I(r_X, r_X, 2), ctx);
+ break;
+ case BPF_S_ST:
+ ctx->seen |= SEEN_MEM_WORD(k);
+ emit(ARM_STR_I(r_A, ARM_SP, SCRATCH_OFF(k)), ctx);
+ break;
+ case BPF_S_STX:
+ ctx->seen |= SEEN_MEM_WORD(k) | SEEN_X;
+ emit(ARM_STR_I(r_X, ARM_SP, SCRATCH_OFF(k)), ctx);
+ break;
+ case BPF_S_ALU_ADD_K:
+ /* A += K */
+ OP_IMM3(ARM_ADD, r_A, r_A, k, ctx);
+ break;
+ case BPF_S_ALU_ADD_X:
+ ctx->seen |= SEEN_X;
+ emit(ARM_ADD_R(r_A, r_A, r_X), ctx);
+ break;
+ case BPF_S_ALU_SUB_K:
+ /* A -= K */
+ OP_IMM3(ARM_SUB, r_A, r_A, k, ctx);
+ break;
+ case BPF_S_ALU_SUB_X:
+ ctx->seen |= SEEN_X;
+ emit(ARM_SUB_R(r_A, r_A, r_X), ctx);
+ break;
+ case BPF_S_ALU_MUL_K:
+ /* A *= K */
+ emit_mov_i(r_scratch, k, ctx);
+ emit(ARM_MUL(r_A, r_A, r_scratch), ctx);
+ break;
+ case BPF_S_ALU_MUL_X:
+ ctx->seen |= SEEN_X;
+ emit(ARM_MUL(r_A, r_A, r_X), ctx);
+ break;
+ case BPF_S_ALU_DIV_K:
+ /* current k == reciprocal_value(userspace k) */
+ emit_mov_i(r_scratch, k, ctx);
+ /* A = top 32 bits of the product */
+ emit(ARM_UMULL(r_scratch, r_A, r_A, r_scratch), ctx);
+ break;
+ case BPF_S_ALU_DIV_X:
+ ctx->seen |= SEEN_X;
+ emit(ARM_CMP_I(r_X, 0), ctx);
+ emit_err_ret(ARM_COND_EQ, ctx);
+ emit_udiv(r_A, r_A, r_X, ctx);
+ break;
+ case BPF_S_ALU_OR_K:
+ /* A |= K */
+ OP_IMM3(ARM_ORR, r_A, r_A, k, ctx);
+ break;
+ case BPF_S_ALU_OR_X:
+ ctx->seen |= SEEN_X;
+ emit(ARM_ORR_I(r_A, r_A, r_X), ctx);
+ break;
+ case BPF_S_ALU_AND_K:
+ /* A &= K */
+ OP_IMM3(ARM_AND, r_A, r_A, k, ctx);
+ break;
+ case BPF_S_ALU_AND_X:
+ ctx->seen |= SEEN_X;
+ emit(ARM_AND_R(r_A, r_A, r_X), ctx);
+ break;
+ case BPF_S_ALU_LSH_K:
+ if (unlikely(k > 31))
+ return -1;
+ emit(ARM_LSL_I(r_A, r_A, k), ctx);
+ break;
+ case BPF_S_ALU_LSH_X:
+ ctx->seen |= SEEN_X;
+ emit(ARM_LSL_R(r_A, r_A, r_X), ctx);
+ break;
+ case BPF_S_ALU_RSH_K:
+ if (unlikely(k > 31))
+ return -1;
+ emit(ARM_LSR_I(r_A, r_A, k), ctx);
+ break;
+ case BPF_S_ALU_RSH_X:
+ ctx->seen |= SEEN_X;
+ emit(ARM_LSR_R(r_A, r_A, r_X), ctx);
+ break;
+ case BPF_S_JMP_JA:
+ /* pc += K */
+ emit(ARM_B(b_imm(i + k, ctx)), ctx);
+ break;
+ case BPF_S_JMP_JEQ_K:
+ /* pc += (A == K) ? pc->jt : pc->jf */
+ condt = ARM_COND_EQ;
+ condf = ARM_COND_NE;
+ goto cmp_imm;
+ case BPF_S_JMP_JGT_K:
+ /* pc += (A > K) ? pc->jt : pc->jf */
+ condt = ARM_COND_HI;
+ condf = ARM_COND_LS;
+ goto cmp_imm;
+ case BPF_S_JMP_JGE_K:
+ /* pc += (A >= K) ? pc->jt : pc->jf */
+ condt = ARM_COND_HI;
+ condf = ARM_COND_LS;
+ /* (x >= y) IFF (x > y - 1) */
+ if (unlikely(k == 0))
+ return -1;
+ k--;
+cmp_imm:
+ imm12 = imm8m(k);
+ if (imm12 < 0) {
+ emit_mov_i_no8m(r_scratch, k, ctx);
+ emit(ARM_CMP_R(r_A, r_scratch), ctx);
+ } else {
+ emit(ARM_CMP_I(r_A, imm12), ctx);
+ }
+cond_jump:
+ if (inst->jt)
+ _emit(condt, ARM_B(b_imm(i + inst->jt + 1,
+ ctx)), ctx);
+ if (inst->jf)
+ _emit(condf, ARM_B(b_imm(i + inst->jf + 1,
+ ctx)), ctx);
+ break;
+ case BPF_S_JMP_JEQ_X:
+ /* pc += (A == X) ? pc->jt : pc->jf */
+ condt = ARM_COND_EQ;
+ condf = ARM_COND_NE;
+ goto cmp_x;
+ case BPF_S_JMP_JGT_X:
+ /* pc += (A > X) ? pc->jt : pc->jf */
+ condt = ARM_COND_HI;
+ condf = ARM_COND_LS;
+ goto cmp_x;
+ case BPF_S_JMP_JGE_X:
+ /* pc += (A >= X) ? pc->jt : pc->jf */
+ condt = ARM_COND_CS;
+ condf = ARM_COND_CC;
+cmp_x:
+ ctx->seen |= SEEN_X;
+ emit(ARM_CMP_R(r_A, r_X), ctx);
+ goto cond_jump;
+ case BPF_S_JMP_JSET_K:
+ /* pc += (A & K) ? pc->jt : pc->jf */
+ condt = ARM_COND_NE;
+ /* not set iff all zeroes iff Z==1 iff EQ */
+ condf = ARM_COND_EQ;
+
+ imm12 = imm8m(k);
+ if (imm12 < 0) {
+ emit_mov_i_no8m(r_scratch, k, ctx);
+ emit(ARM_TST_R(r_A, r_scratch), ctx);
+ } else {
+ emit(ARM_TST_I(r_A, imm12), ctx);
+ }
+ goto cond_jump;
+ case BPF_S_JMP_JSET_X:
+ /* pc += (A & X) ? pc->jt : pc->jf */
+ condt = ARM_COND_NE;
+ condf = ARM_COND_EQ;
+ emit(ARM_TST_R(r_A, r_X), ctx);
+ goto cond_jump;
+ case BPF_S_RET_A:
+ emit(ARM_MOV_R(ARM_R0, r_A), ctx);
+ goto b_epilogue;
+ case BPF_S_RET_K:
+ if ((k == 0) && (ctx->ret0_fp_idx < 0))
+ ctx->ret0_fp_idx = i;
+ emit_mov_i(ARM_R0, k, ctx);
+b_epilogue:
+ if (i != ctx->skf->len - 1)
+ emit(ARM_B(b_imm(prog->len, ctx)), ctx);
+ break;
+ case BPF_S_MISC_TAX:
+ /* X = A */
+ emit(ARM_MOV_R(r_X, r_A), ctx);
+ break;
+ case BPF_S_MISC_TXA:
+ /* A = X */
+ emit(ARM_MOV_R(r_A, r_X), ctx);
+ break;
+ case BPF_S_ANC_PROTOCOL:
+ /* A = ntohs(skb->protocol) */
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
+ protocol) != 2);
+ off = offsetof(struct sk_buff, protocol);
+ emit(ARM_LDRH_I(r_scratch, r_skb, off), ctx);
+ emit_swap16(r_A, r_scratch, ctx);
+ break;
+ case BPF_S_ANC_CPU:
+ /* A = current_thread_info()->cpu */
+ emit_mov_i(r_scratch, (~(THREAD_SIZE - 1)), ctx);
+ emit(ARM_ADD_R(r_scratch, ARM_SP, r_scratch), ctx);
+
+ BUILD_BUG_ON(FIELD_SIZEOF(struct thread_info, cpu) != 4);
+ off = offsetof(struct thread_info, cpu);
+ emit(ARM_LDR_I(r_A, r_scratch, off), ctx);
+ break;
+ case BPF_S_ANC_IFINDEX:
+ /* A = skb->dev->ifindex */
+ off = offsetof(struct sk_buff, dev);
+ emit(ARM_LDR_I(r_scratch, r_skb, off), ctx);
+
+ emit(ARM_CMP_I(r_scratch, 0), ctx);
+ emit_err_ret(ARM_COND_EQ, ctx);
+
+ BUILD_BUG_ON(FIELD_SIZEOF(struct net_device,
+ ifindex) != 4);
+ off = offsetof(struct net_device, ifindex);
+ emit(ARM_LDR_I(r_A, r_scratch, off), ctx);
+ break;
+ case BPF_S_ANC_MARK:
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
+ off = offsetof(struct sk_buff, mark);
+ emit(ARM_LDR_I(r_A, r_skb, off), ctx);
+ break;
+ case BPF_S_ANC_RXHASH:
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
+ off = offsetof(struct sk_buff, rxhash);
+ emit(ARM_LDR_I(r_A, r_skb, off), ctx);
+ break;
+ case BPF_S_ANC_QUEUE:
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
+ queue_mapping) != 2);
+ BUILD_BUG_ON(offsetof(struct sk_buff,
+ queue_mapping) > 0xff);
+ off = offsetof(struct sk_buff, queue_mapping);
+ emit(ARM_LDRH_I(r_A, r_skb, off), ctx);
+ break;
+ default:
+ return -1;
+ }
+ }
+
+ /* compute offsets only during the first pass */
+ if (ctx->target == NULL)
+ ctx->offsets[i] = ctx->idx * 4;
+
+ return 0;
+}
+
+
+void bpf_jit_compile(struct sk_filter *fp)
+{
+ struct jit_ctx ctx;
+ unsigned tmp_idx;
+ unsigned alloc_size;
+
+ if (!bpf_jit_enable)
+ return;
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.skf = fp;
+ ctx.ret0_fp_idx = -1;
+
+ ctx.offsets = kzalloc(GFP_KERNEL, 4 * (ctx.skf->len + 1));
+ if (ctx.offsets == NULL)
+ return;
+
+ /* fake pass to fill in the ctx->seen */
+ if (unlikely(build_body(&ctx)))
+ goto out;
+
+ tmp_idx = ctx.idx;
+ build_prologue(&ctx);
+ ctx.prologue_bytes = (ctx.idx - tmp_idx) * 4;
+
+#if __LINUX_ARM_ARCH__ < 7
+ tmp_idx = ctx.idx;
+ build_epilogue(&ctx);
+ ctx.epilogue_bytes = (ctx.idx - tmp_idx) * 4;
+
+ ctx.idx += ctx.imm_count;
+ if (ctx.imm_count) {
+ ctx.imms = kzalloc(GFP_KERNEL, 4 * ctx.imm_count);
+ if (ctx.imms == NULL)
+ goto out;
+ }
+#else
+ /* there's nothing after the epilogue on ARMv7 */
+ build_epilogue(&ctx);
+#endif
+
+ alloc_size = 4 * ctx.idx;
+ ctx.target = module_alloc(alloc_size > sizeof(struct work_struct) ?
+ alloc_size : sizeof(struct work_struct));
+ if (unlikely(ctx.target == NULL))
+ goto out;
+
+ ctx.idx = 0;
+ build_prologue(&ctx);
+ build_body(&ctx);
+ build_epilogue(&ctx);
+
+ flush_icache_range((u32)ctx.target, (u32)(ctx.target + ctx.idx));
+
+#if __LINUX_ARM_ARCH__ < 7
+ if (ctx.imm_count)
+ kfree(ctx.imms);
+#endif
+
+ if (bpf_jit_enable > 1)
+ print_hex_dump(KERN_INFO, "BPF JIT code: ",
+ DUMP_PREFIX_ADDRESS, 16, 4, ctx.target,
+ alloc_size, false);
+
+ fp->bpf_func = (void *)ctx.target;
+out:
+ kfree(ctx.offsets);
+ return;
+}
+
+static void bpf_jit_free_worker(struct work_struct *work)
+{
+ module_free(NULL, work);
+}
+
+void bpf_jit_free(struct sk_filter *fp)
+{
+ struct work_struct *work;
+
+ if (fp->bpf_func != sk_run_filter) {
+ work = (struct work_struct *)fp->bpf_func;
+
+ INIT_WORK(work, bpf_jit_free_worker);
+ schedule_work(work);
+ }
+}
+
diff --git a/arch/arm/net/bpf_jit_32.h b/arch/arm/net/bpf_jit_32.h
new file mode 100644
index 0000000..d55f3f3
--- /dev/null
+++ b/arch/arm/net/bpf_jit_32.h
@@ -0,0 +1,180 @@
+/*
+ * Just-In-Time compiler for BPF filters on 32bit ARM
+ *
+ * Copyright (c) 2011 Mircea Gherzan <mgherzan@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ */
+
+#ifndef PFILTER_OPCODES_ARM_H
+#define PFILTER_OPCODES_ARM_H
+
+#define ARM_R0 0
+#define ARM_R1 1
+#define ARM_R2 2
+#define ARM_R3 3
+#define ARM_R4 4
+#define ARM_R5 5
+#define ARM_R6 6
+#define ARM_R7 7
+#define ARM_R8 8
+#define ARM_R9 9
+#define ARM_R10 10
+#define ARM_FP 11
+#define ARM_IP 12
+#define ARM_SP 13
+#define ARM_LR 14
+#define ARM_PC 15
+
+#define ARM_COND_EQ 0x0
+#define ARM_COND_NE 0x1
+#define ARM_COND_CS 0x2
+#define ARM_COND_HS ARM_COND_CS
+#define ARM_COND_CC 0x3
+#define ARM_COND_LO ARM_COND_CC
+#define ARM_COND_MI 0x4
+#define ARM_COND_PL 0x5
+#define ARM_COND_VS 0x6
+#define ARM_COND_VC 0x7
+#define ARM_COND_HI 0x8
+#define ARM_COND_LS 0x9
+#define ARM_COND_GE 0xa
+#define ARM_COND_LT 0xb
+#define ARM_COND_GT 0xc
+#define ARM_COND_LE 0xd
+#define ARM_COND_AL 0xe
+
+/* register shift types */
+#define SRTYPE_LSL 0
+#define SRTYPE_LSR 1
+#define SRTYPE_ASR 2
+#define SRTYPE_ROR 3
+
+#define ARM_INST_ADD_R 0x00800000
+#define ARM_INST_ADD_I 0x02800000
+
+#define ARM_INST_AND_R 0x00000000
+#define ARM_INST_AND_I 0x02000000
+
+#define ARM_INST_B 0x0a000000
+#define ARM_INST_BX 0x012FFF10
+#define ARM_INST_BLX_R 0x012fff30
+
+#define ARM_INST_CMP_R 0x01500000
+#define ARM_INST_CMP_I 0x03500000
+
+#define ARM_INST_LDRB_I 0x05d00000
+#define ARM_INST_LDRB_R 0x07d00000
+#define ARM_INST_LDRH_I 0x01d000b0
+#define ARM_INST_LDR_I 0x05900000
+
+#define ARM_INST_LDM 0x08900000
+
+#define ARM_INST_LSL_I 0x01a00000
+#define ARM_INST_LSL_R 0x01a00010
+
+#define ARM_INST_LSR_I 0x01a00020
+#define ARM_INST_LSR_R 0x01a00030
+
+#define ARM_INST_MOV_R 0x01a00000
+#define ARM_INST_MOV_I 0x03a00000
+#define ARM_INST_MOVW 0x03000000
+#define ARM_INST_MOVT 0x03400000
+
+#define ARM_INST_MUL 0x00000090
+
+#define ARM_INST_POP 0x08bd0000
+#define ARM_INST_PUSH 0x092d0000
+
+#define ARM_INST_REV 0x06bf0f30
+#define ARM_INST_REV16 0x06bf0fb0
+
+#define ARM_INST_ORR_R 0x01800000
+#define ARM_INST_ORR_I 0x03800000
+
+#define ARM_INST_SUB_R 0x00400000
+#define ARM_INST_SUB_I 0x02400000
+
+#define ARM_INST_STR_I 0x05800000
+
+#define ARM_INST_TST_R 0x01100000
+#define ARM_INST_TST_I 0x03100000
+
+#define ARM_INST_UDIV 0x0730f010
+
+#define ARM_INST_UMULL 0x00800090
+
+/* register */
+#define _AL3_R(op, rd, rn, rm) ((op ## _R) | (rd) << 12 | (rn) << 16 | (rm))
+/* immediate */
+#define _AL3_I(op, rd, rn, imm) ((op ## _I) | (rd) << 12 | (rn) << 16 | (imm))
+
+#define ARM_ADD_R(rd, rn, rm) _AL3_R(ARM_INST_ADD, rd, rn, rm)
+#define ARM_ADD_I(rd, rn, imm) _AL3_I(ARM_INST_ADD, rd, rn, imm)
+
+#define ARM_AND_R(rd, rn, rm) _AL3_R(ARM_INST_AND, rd, rn, rm)
+#define ARM_AND_I(rd, rn, imm) _AL3_I(ARM_INST_AND, rd, rn, imm)
+
+#define ARM_B(imm24) (ARM_INST_B | (imm24))
+#define ARM_BX(rm) (ARM_INST_BX | (rm))
+#define ARM_BLX_R(rm) (ARM_INST_BLX_R | (rm))
+
+#define ARM_CMP_R(rn, rm) _AL3_R(ARM_INST_CMP, 0, rn, rm)
+#define ARM_CMP_I(rn, imm) _AL3_I(ARM_INST_CMP, 0, rn, imm)
+
+#define ARM_LDR_I(rt, rn, off) (ARM_INST_LDR_I | (rt) << 12 | (rn) << 16 \
+ | (off))
+#define ARM_LDRB_I(rt, rn, off) (ARM_INST_LDRB_I | (rt) << 12 | (rn) << 16 \
+ | (off))
+#define ARM_LDRB_R(rt, rn, rm) (ARM_INST_LDRB_R | (rt) << 12 | (rn) << 16 \
+ | (rm))
+#define ARM_LDRH_I(rt, rn, off) (ARM_INST_LDRH_I | (rt) << 12 | (rn) << 16 \
+ | (((off) & 0xf0) << 4) | ((off) & 0xf))
+
+#define ARM_LDM(rn, regs) (ARM_INST_LDM | (rn) << 16 | (regs))
+
+#define ARM_LSL_R(rd, rn, rm) (_AL3_R(ARM_INST_LSL, rd, 0, rn) | (rm) << 8)
+#define ARM_LSL_I(rd, rn, imm) (_AL3_R(ARM_INST_LSL, rd, 0, rn) | (imm) << 7)
+
+#define ARM_LSR_R(rd, rn, rm) (_AL3_R(ARM_INST_LSR, rd, 0, rn) | (rm) << 8)
+#define ARM_LSR_I(rd, rn, imm) (_AL3_R(ARM_INST_LSR, rd, 0, rn) | (imm) << 7)
+
+#define ARM_MOV_R(rd, rm) _AL3_R(ARM_INST_MOV, rd, 0, rm)
+#define ARM_MOV_I(rd, imm) _AL3_I(ARM_INST_MOV, rd, 0, imm)
+
+#define ARM_MOVW(rd, imm) \
+ (ARM_INST_MOVW | ((imm) >> 12) << 16 | (rd) << 12 | ((imm) & 0x0fff))
+
+#define ARM_MOVT(rd, imm) \
+ (ARM_INST_MOVT | ((imm) >> 12) << 16 | (rd) << 12 | ((imm) & 0x0fff))
+
+#define ARM_MUL(rd, rm, rn) (ARM_INST_MUL | (rd) << 16 | (rm) << 8 | (rn))
+
+#define ARM_POP(regs) (ARM_INST_POP | (regs))
+#define ARM_PUSH(regs) (ARM_INST_PUSH | (regs))
+
+#define ARM_ORR_R(rd, rn, rm) _AL3_R(ARM_INST_ORR, rd, rn, rm)
+#define ARM_ORR_I(rd, rn, imm) _AL3_I(ARM_INST_ORR, rd, rn, imm)
+#define ARM_ORR_S(rd, rn, rm, type, rs) \
+ (ARM_ORR_R(rd, rn, rm) | (type) << 5 | (rs) << 7)
+
+#define ARM_REV(rd, rm) (ARM_INST_REV | (rd) << 12 | (rm))
+#define ARM_REV16(rd, rm) (ARM_INST_REV16 | (rd) << 12 | (rm))
+
+#define ARM_SUB_R(rd, rn, rm) _AL3_R(ARM_INST_SUB, rd, rn, rm)
+#define ARM_SUB_I(rd, rn, imm) _AL3_I(ARM_INST_SUB, rd, rn, imm)
+
+#define ARM_STR_I(rt, rn, off) (ARM_INST_STR_I | (rt) << 12 | (rn) << 16 \
+ | (off))
+
+#define ARM_TST_R(rn, rm) _AL3_R(ARM_INST_TST, 0, rn, rm)
+#define ARM_TST_I(rn, imm) _AL3_I(ARM_INST_TST, 0, rn, imm)
+
+#define ARM_UDIV(rd, rn, rm) (ARM_INST_UDIV | (rd) << 16 | (rn) | (rm) << 8)
+
+#define ARM_UMULL(rd_lo, rd_hi, rn, rm) (ARM_INST_UMULL | (rd_hi) << 16 \
+ | (rd_lo) << 12 | (rm) << 8 | rn)
+
+#endif /* PFILTER_OPCODES_ARM_H */
--
1.7.7.3
^ permalink raw reply related
* [PATCH] mqprio: Avoid panic if no options are provided
From: Thomas Graf @ 2011-12-22 12:05 UTC (permalink / raw)
To: davem; +Cc: netdev, john.r.fastabend, Thomas Graf
Userspace may not provide TCA_OPTIONS, in fact tc currently does
so not do so if no arguments are specified on the command line.
Return EINVAL instead of panicing.
Signed-off-by: Thomas Graf <tgraf@redhat.com>
---
net/sched/sch_mqprio.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c
index f88256c..28de430 100644
--- a/net/sched/sch_mqprio.c
+++ b/net/sched/sch_mqprio.c
@@ -107,7 +107,7 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt)
if (!netif_is_multiqueue(dev))
return -EOPNOTSUPP;
- if (nla_len(opt) < sizeof(*qopt))
+ if (!opt || nla_len(opt) < sizeof(*qopt))
return -EINVAL;
qopt = nla_data(opt);
--
1.7.7.4
^ permalink raw reply related
* Re: [PATCH, v2] Xen: consolidate and simplify struct xenbus_driver instantiation
From: Ian Campbell @ 2011-12-22 11:57 UTC (permalink / raw)
To: Jan Beulich
Cc: Konrad Rzeszutek Wilk, davem@davemloft.net,
dmitry.torokhov@gmail.com, FlorianSchandinat@gmx.de,
Jeremy Fitzhardinge, Jens Axboe, xen-devel@lists.xensource.com,
Konrad Rzeszutek Wilk, linux-kernel@vger.kernel.org,
netdev@vger.kernel.org
In-Reply-To: <4EF327E2020000780006993E@nat28.tlf.novell.com>
On Thu, 2011-12-22 at 11:51 +0000, Jan Beulich wrote:
> >>> On 22.12.11 at 10:57, Ian Campbell <Ian.Campbell@citrix.com> wrote:
> > On Thu, 2011-12-22 at 09:08 +0000, Jan Beulich wrote:
> >> The 'name', 'owner', and 'mod_name' members are redundant with the
> >> identically named fields in the 'driver' sub-structure. Rather than
> >> switching each instance to specify these fields explicitly, introduce
> >> a macro to simplify this.
> >>
> >> Eliminate further redundancy by allowing the drvname argument to
> >> DEFINE_XENBUS_DRIVER() to be blank (in which case the first entry from
> >> the ID table will be used for .driver.name).
> >
> > Any reason not to always use DRV_NAME here (which is generally a bit
> > more specific e.g. "xen-foofront" rather than "foo") and rely on the id
> > table for the shorter names used in xenstore?
>
> That would imply that DRV_NAME is always defined, but I don't
> see this being the case.
My mistake, I thought it was a Kbuild thing.
Ian.
^ permalink raw reply
* Re: [PATCH, v2] Xen: consolidate and simplify struct xenbus_driver instantiation
From: Jan Beulich @ 2011-12-22 11:51 UTC (permalink / raw)
To: Ian Campbell
Cc: Konrad Rzeszutek Wilk, davem@davemloft.net,
dmitry.torokhov@gmail.com, FlorianSchandinat@gmx.de,
Jeremy Fitzhardinge, Jens Axboe, xen-devel@lists.xensource.com,
Konrad Rzeszutek Wilk, linux-kernel@vger.kernel.org,
netdev@vger.kernel.org
In-Reply-To: <1324547820.7877.71.camel@zakaz.uk.xensource.com>
>>> On 22.12.11 at 10:57, Ian Campbell <Ian.Campbell@citrix.com> wrote:
> On Thu, 2011-12-22 at 09:08 +0000, Jan Beulich wrote:
>> The 'name', 'owner', and 'mod_name' members are redundant with the
>> identically named fields in the 'driver' sub-structure. Rather than
>> switching each instance to specify these fields explicitly, introduce
>> a macro to simplify this.
>>
>> Eliminate further redundancy by allowing the drvname argument to
>> DEFINE_XENBUS_DRIVER() to be blank (in which case the first entry from
>> the ID table will be used for .driver.name).
>
> Any reason not to always use DRV_NAME here (which is generally a bit
> more specific e.g. "xen-foofront" rather than "foo") and rely on the id
> table for the shorter names used in xenstore?
That would imply that DRV_NAME is always defined, but I don't
see this being the case.
Jan
^ permalink raw reply
* [PATCH v2] Partial revert "Basic kernel memory functionality for the Memory Controller"
From: Glauber Costa @ 2011-12-22 11:02 UTC (permalink / raw)
To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
kamezawa.hiroyu-+CUm20s59erQFUHtdCDX3A,
netdev-u79uwXL29TY76Z2rM5mHXA,
eric.dumazet-Re5JQEeQqe8AvxtiuMwx3w,
cgroups-u79uwXL29TY76Z2rM5mHXA, Glauber Costa, Kirill A. Shutemov,
Paul Menage, Greg Thelen, Johannes Weiner
This reverts commit e5671dfae59b165e2adfd4dfbdeab11ac8db5bda.
After a follow up discussion with Michal, it was agreed it would
be better to leave the kmem controller with just the tcp files,
deferring the behavior of the other general memory.kmem.* files
for a later time, when more caches are controlled. This is because
generic kmem files are not used by tcp accounting and it is
not clear how other slab caches would fit into the scheme.
We are reverting the original commit so we can track the reference.
Part of the patch is kept, because it was used by the later tcp
code. Conflicts are shown in the bottom. init/Kconfig is removed from
the revert entirely.
Signed-off-by: Glauber Costa <glommer-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
Acked-by: Michal Hocko <mhocko-AlSwsSmVLrQ@public.gmane.org>
CC: Kirill A. Shutemov <kirill-oKw7cIdHH8eLwutG50LtGA@public.gmane.org>
CC: Paul Menage <paul-inf54ven1CmVyaH7bEyXVA@public.gmane.org>
CC: Greg Thelen <gthelen-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
CC: Johannes Weiner <jweiner-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
CC: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
Conflicts:
Documentation/cgroups/memory.txt
mm/memcontrol.c
---
Documentation/cgroups/memory.txt | 22 +--------
mm/memcontrol.c | 93 +++-----------------------------------
2 files changed, 8 insertions(+), 107 deletions(-)
diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt
index 6922b6c..4d8774f 100644
--- a/Documentation/cgroups/memory.txt
+++ b/Documentation/cgroups/memory.txt
@@ -44,9 +44,8 @@ Features:
- oom-killer disable knob and oom-notifier
- Root cgroup has no limit controls.
- Hugepages is not under control yet. We just manage pages on LRU. To add more
- controls, we have to take care of performance. Kernel memory support is work
- in progress, and the current version provides basically functionality.
+ Kernel memory support is work in progress, and the current version provides
+ basically functionality. (See Section 2.7)
Brief summary of control files.
@@ -57,11 +56,8 @@ Brief summary of control files.
(See 5.5 for details)
memory.memsw.usage_in_bytes # show current res_counter usage for memory+Swap
(See 5.5 for details)
- memory.kmem.usage_in_bytes # show current res_counter usage for kmem only.
- (See 2.7 for details)
memory.limit_in_bytes # set/show limit of memory usage
memory.memsw.limit_in_bytes # set/show limit of memory+Swap usage
- memory.kmem.limit_in_bytes # if allowed, set/show limit of kernel memory
memory.failcnt # show the number of memory usage hits limits
memory.memsw.failcnt # show the number of memory+Swap hits limits
memory.max_usage_in_bytes # show max memory usage recorded
@@ -76,8 +72,6 @@ Brief summary of control files.
memory.oom_control # set/show oom controls.
memory.numa_stat # show the number of memory usage per numa node
- memory.independent_kmem_limit # select whether or not kernel memory limits are
- independent of user limits
memory.kmem.tcp.limit_in_bytes # set/show hard limit for tcp buf memory
memory.kmem.tcp.usage_in_bytes # show current tcp buf memory allocation
@@ -271,21 +265,9 @@ the amount of kernel memory used by the system. Kernel memory is fundamentally
different than user memory, since it can't be swapped out, which makes it
possible to DoS the system by consuming too much of this precious resource.
-Some kernel memory resources may be accounted and limited separately from the
-main "kmem" resource. For instance, a slab cache that is considered important
-enough to be limited separately may have its own knobs.
-
Kernel memory limits are not imposed for the root cgroup. Usage for the root
cgroup may or may not be accounted.
-Memory limits as specified by the standard Memory Controller may or may not
-take kernel memory into consideration. This is achieved through the file
-memory.independent_kmem_limit. A Value different than 0 will allow for kernel
-memory to be controlled separately.
-
-When kernel memory limits are not independent, the limit values set in
-memory.kmem files are ignored.
-
Currently no soft limit is implemented for kernel memory. It is future work
to trigger slab reclaim when those limits are reached.
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 7266202..8cdc915 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -229,10 +229,6 @@ struct mem_cgroup {
*/
struct res_counter memsw;
/*
- * the counter to account for kmem usage.
- */
- struct res_counter kmem;
- /*
* Per cgroup active and inactive list, similar to the
* per zone LRU lists.
*/
@@ -283,11 +279,6 @@ struct mem_cgroup {
*/
unsigned long move_charge_at_immigrate;
/*
- * Should kernel memory limits be stabilished independently
- * from user memory ?
- */
- int kmem_independent_accounting;
- /*
* percpu counter.
*/
struct mem_cgroup_stat_cpu *stat;
@@ -359,14 +350,9 @@ enum charge_type {
};
/* for encoding cft->private value on file */
-
-enum mem_type {
- _MEM = 0,
- _MEMSWAP,
- _OOM_TYPE,
- _KMEM,
-};
-
+#define _MEM (0)
+#define _MEMSWAP (1)
+#define _OOM_TYPE (2)
#define MEMFILE_PRIVATE(x, val) (((x) << 16) | (val))
#define MEMFILE_TYPE(val) (((val) >> 16) & 0xffff)
#define MEMFILE_ATTR(val) ((val) & 0xffff)
@@ -3919,17 +3905,10 @@ static inline u64 mem_cgroup_usage(struct mem_cgroup *memcg, bool swap)
u64 val;
if (!mem_cgroup_is_root(memcg)) {
- val = 0;
-#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM
- if (!memcg->kmem_independent_accounting)
- val = res_counter_read_u64(&memcg->kmem, RES_USAGE);
-#endif
if (!swap)
- val += res_counter_read_u64(&memcg->res, RES_USAGE);
+ return res_counter_read_u64(&memcg->res, RES_USAGE);
else
- val += res_counter_read_u64(&memcg->memsw, RES_USAGE);
-
- return val;
+ return res_counter_read_u64(&memcg->memsw, RES_USAGE);
}
val = mem_cgroup_recursive_stat(memcg, MEM_CGROUP_STAT_CACHE);
@@ -3962,11 +3941,6 @@ static u64 mem_cgroup_read(struct cgroup *cont, struct cftype *cft)
else
val = res_counter_read_u64(&memcg->memsw, name);
break;
-#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM
- case _KMEM:
- val = res_counter_read_u64(&memcg->kmem, name);
- break;
-#endif
default:
BUG();
break;
@@ -4696,59 +4670,8 @@ static int mem_control_numa_stat_open(struct inode *unused, struct file *file)
#endif /* CONFIG_NUMA */
#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM
-static u64 kmem_limit_independent_read(struct cgroup *cgroup, struct cftype *cft)
-{
- return mem_cgroup_from_cont(cgroup)->kmem_independent_accounting;
-}
-
-static int kmem_limit_independent_write(struct cgroup *cgroup, struct cftype *cft,
- u64 val)
-{
- struct mem_cgroup *memcg = mem_cgroup_from_cont(cgroup);
- struct mem_cgroup *parent = parent_mem_cgroup(memcg);
-
- val = !!val;
-
- /*
- * This follows the same hierarchy restrictions than
- * mem_cgroup_hierarchy_write()
- */
- if (!parent || !parent->use_hierarchy) {
- if (list_empty(&cgroup->children))
- memcg->kmem_independent_accounting = val;
- else
- return -EBUSY;
- }
- else
- return -EINVAL;
-
- return 0;
-}
-static struct cftype kmem_cgroup_files[] = {
- {
- .name = "independent_kmem_limit",
- .read_u64 = kmem_limit_independent_read,
- .write_u64 = kmem_limit_independent_write,
- },
- {
- .name = "kmem.usage_in_bytes",
- .private = MEMFILE_PRIVATE(_KMEM, RES_USAGE),
- .read_u64 = mem_cgroup_read,
- },
- {
- .name = "kmem.limit_in_bytes",
- .private = MEMFILE_PRIVATE(_KMEM, RES_LIMIT),
- .read_u64 = mem_cgroup_read,
- },
-};
-
static int register_kmem_files(struct cgroup *cont, struct cgroup_subsys *ss)
{
- int ret = 0;
-
- ret = cgroup_add_files(cont, ss, kmem_cgroup_files,
- ARRAY_SIZE(kmem_cgroup_files));
-
/*
* Part of this would be better living in a separate allocation
* function, leaving us with just the cgroup tree population work.
@@ -4756,9 +4679,7 @@ static int register_kmem_files(struct cgroup *cont, struct cgroup_subsys *ss)
* is only initialized after cgroup creation. I found the less
* cumbersome way to deal with it to defer it all to populate time
*/
- if (!ret)
- ret = mem_cgroup_sockets_init(cont, ss);
- return ret;
+ return mem_cgroup_sockets_init(cont, ss);
};
static void kmem_cgroup_destroy(struct cgroup_subsys *ss,
@@ -5092,7 +5013,6 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
if (parent && parent->use_hierarchy) {
res_counter_init(&memcg->res, &parent->res);
res_counter_init(&memcg->memsw, &parent->memsw);
- res_counter_init(&memcg->kmem, &parent->kmem);
/*
* We increment refcnt of the parent to ensure that we can
* safely access it on res_counter_charge/uncharge.
@@ -5103,7 +5023,6 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
} else {
res_counter_init(&memcg->res, NULL);
res_counter_init(&memcg->memsw, NULL);
- res_counter_init(&memcg->kmem, NULL);
}
memcg->last_scanned_child = 0;
memcg->last_scanned_node = MAX_NUMNODES;
--
1.7.6.4
^ permalink raw reply related
* Re: [PATCH] Partial revert "Basic kernel memory functionality for the Memory Controller"
From: Michal Hocko @ 2011-12-22 10:59 UTC (permalink / raw)
To: Glauber Costa
Cc: davem, linux-kernel, kamezawa.hiroyu, netdev, eric.dumazet,
cgroups, Kirill A. Shutemov, Paul Menage, Greg Thelen,
Johannes Weiner
In-Reply-To: <4EF309F0.90407@parallels.com>
On Thu 22-12-11 14:44:00, Glauber Costa wrote:
> On 12/22/2011 02:43 PM, Michal Hocko wrote:
> >On Thu 22-12-11 12:53:10, Glauber Costa wrote:
> >>This reverts commit e5671dfae59b165e2adfd4dfbdeab11ac8db5bda.
> >>
> >>After a follow up discussion with Michal, it was agreed it would
> >>be better to leave the kmem controller with just the tcp files,
> >>deferring the behavior of the other general memory.kmem.* files
> >>for a later time, when more caches are controlled.
> >
> >"Because generic kmem files are not used by tcp accounting and it is
> >not clear how other slab caches would fit into the scheme."
>
> Should I respin?
Yes, please
[...]
Thanks
--
Michal Hocko
SUSE Labs
SUSE LINUX s.r.o.
Lihovarska 1060/12
190 00 Praha 9
Czech Republic
^ permalink raw reply
* [PATCH] drivers/net/usb/asix: fixed asix_get_wol reported wrong wol status issue
From: ASIX Allan Email [office] @ 2011-12-22 10:56 UTC (permalink / raw)
To: davem
Cc: netdev, linux-kernel, 'Freddy Xin',
'Grant Grundler', 'Eugene',
'ASIX Louis [蘇威陸]'
Dear David,
This is my first time to submit the driver patch onto Linux kernel mainline source. Please correct me if anything is wrong on my submission way or email format. Thanks a lot for your great helps.
========
Fixed the asix_get_wol() routine reported wrong wol status issue.
This fix had been verified on x86 Linux kernel 3.0.0-12-generic system with AX88772A/AX88772/Belkin AX88178 USB dongles, and the wol function works fine (can be waked up by receiving the magic packets).
Signed-off-by: Allan Chou <allan@asix.com.tw>
Tested-by: Allan Chou <allan@asix.com.tw>
---
diff --uprN a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
--- a/drivers/net/usb/asix.c 2011-12-15 14:01:49.000000000 +0800
+++ b/drivers/net/usb/asix.c 2011-12-22 18:20:39.000000000 +0800
@@ -36,7 +36,7 @@
#include <linux/usb/usbnet.h>
#include <linux/slab.h>
-#define DRIVER_VERSION "08-Nov-2011"
+#define DRIVER_VERSION "22-Dec-2011"
#define DRIVER_NAME "asix"
/* ASIX AX8817X based USB 2.0 Ethernet Devices */
@@ -689,6 +689,10 @@ asix_get_wol(struct net_device *net, str
}
wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
wolinfo->wolopts = 0;
+ if (opt & AX_MONITOR_LINK)
+ wolinfo->wolopts |= WAKE_PHY;
+ if (opt & AX_MONITOR_MAGIC)
+ wolinfo->wolopts |= WAKE_MAGIC;
}
static int
---
Best regards,
Allan Chou
Technical Support Division
ASIX Electronics Corporation
TEL: 886-3-5799500 ext.228
FAX: 886-3-5799558
E-mail: allan@asix.com.tw
http://www.asix.com.tw/
-----Original Message-----
From: allan [mailto:allan@asix.com.tw]
Sent: Saturday, December 17, 2011 10:36 AM
To: 'Grant Grundler'
Cc: 'Eugene'; 'netdev@vger.kernel.org'; 'Freddy Xin'; 'ASIX Louis [蘇威陸]'
Subject: RE: drivers/net/usb/asix: bug in asix_get_wol
Dear Grant,
I will double check this issue and submit the revised patch to Linux kernel mainline source next week. Thanks a lot for your great helps.
---
Best regards,
Allan Chou
Technical Support Division
ASIX Electronics Corporation
TEL: 886-3-5799500 ext.228
FAX: 886-3-5799558
E-mail: allan@asix.com.tw
http://www.asix.com.tw/
-----Original Message-----
From: grundler@google.com [mailto:grundler@google.com] On Behalf Of Grant Grundler
Sent: Saturday, December 17, 2011 6:16 AM
To: ASIX Allan Email [office]
Cc: Eugene; netdev@vger.kernel.org; Freddy Xin; ASIX Louis [蘇威陸]
Subject: Re: drivers/net/usb/asix: bug in asix_get_wol
On Thu, Dec 15, 2011 at 9:15 PM, ASIX Allan Email [office]
<allan@asix.com.tw> wrote:
> Resend without attachment due to below email server error.
...
> -----Original Message-----
> From: ASIX Allan Email [office] [mailto:allan@asix.com.tw]
> Sent: Friday, December 16, 2011 11:38 AM
> To: 'Grant Grundler'; 'Eugene'
> Cc: 'netdev@vger.kernel.org'; 'Freddy Xin'; ASIX Louis [蘇威陸]
> Subject: RE: drivers/net/usb/asix: bug in asix_get_wol
> Importance: High
>
> Dear Grant and Eugene,
>
> Please refer to the attached file and below statements to modify the
> asix_get_wol() routine and let us know if this suggestion can solve
> your issues or not? Thanks a lot.
Allan,
Thanks for the response but it doesn't answer my previous question.
Let me ask the same question differently.
Does WOL support in asix driver need more than the four lines of code?
Ie does MONITOR_MODE need to be enabled or anything like that?
> ================
> static void
> asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
> {
> struct usbnet *dev = netdev_priv(net);
> u8 opt;
>
> if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) {
> wolinfo->supported = 0;
> wolinfo->wolopts = 0;
> return;
> }
> wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
> wolinfo->wolopts = 0;
> if (opt & AX_MONITOR_LINK)
> wolinfo->wolopts |= WAKE_PHY;
> if (opt & AX_MONITOR_MAGIC)
> wolinfo->wolopts |= WAKE_MAGIC;
> }
This looks remarkably similar to the code Eugene said enables WOL for
him (and it works). I not able to find any difference.
If you believe it was a mistake to remove these four lines of code,
please submit a patch (See Documentation/SubmittingPatches) to add
them back. You can add a "Tested-by: Eugene <elubarsky@gmail.com>"
line after your own "Signed-off-by:" in the patch.
thanks!
grant
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox