* Re: [PATCH 05/10] net: move destructor_arg to the front of sk_buff.
From: Ian Campbell @ 2012-04-11 8:00 UTC (permalink / raw)
To: Alexander Duyck
Cc: Eric Dumazet, netdev@vger.kernel.org, David Miller,
Michael S. Tsirkin, Wei Liu (Intern), xen-devel@lists.xen.org
In-Reply-To: <4F8486E7.5050604@intel.com>
On Tue, 2012-04-10 at 20:15 +0100, Alexander Duyck wrote:
> On 04/10/2012 11:41 AM, Eric Dumazet wrote:
> > On Tue, 2012-04-10 at 11:33 -0700, Alexander Duyck wrote:
> >
> >> Have you checked this for 32 bit as well as 64? Based on my math your
> >> next patch will still mess up the memset on 32 bit with the structure
> >> being split somewhere just in front of hwtstamps.
> >>
> >> Why not just take frags and move it to the start of the structure? It
> >> is already an unknown value because it can be either 16 or 17 depending
> >> on the value of PAGE_SIZE, and since you are making changes to frags the
> >> changes wouldn't impact the alignment of the other values later on since
> >> you are aligning the end of the structure. That way you would be
> >> guaranteed that all of the fields that will be memset would be in the
> >> last 64 bytes.
> >>
> > Now when a fragmented packet is copied in pskb_expand_head(), you access
> > two separate zones of memory to copy the shinfo. But its supposed to be
> > slow path.
> >
> > Problem with this is that the offsets of often used fields will be big
> > (instead of being < 127) and code will be bigger on x86.
>
> Actually now that I think about it my concerns go much further than the
> memset. I'm convinced that this is going to cause a pretty significant
> performance regression on multiple drivers, especially on non x86_64
> architecture. What we have right now on most platforms is a
> skb_shared_info structure in which everything up to and including frag 0
> is all in one cache line. This gives us pretty good performance for igb
> and ixgbe since that is our common case when jumbo frames are not
> enabled is to split the head and place the data in a page.
With all the changes in this series it is still possible to fit a
maximum standard MTU frame and the shinfo on the same 4K page while also
have the skb_shared_info up to and including frag [0] aligned to the
same 64 byte cache line.
The only exception is destructor_arg on 64 bit which is on the preceding
cache line but that is not a field used in any hot path.
> However the change being recommend here only resolves the issue for one
> specific architecture, and that is what I don't agree with. What we
> need is a solution that also works for 64K pages or 32 bit pointers and
> I am fairly certain this current solution does not.
I think it does work for 32 bit pointers. What issue to do you see with
64K pages?
Ian.
^ permalink raw reply
* Re: [PATCH 05/10] net: move destructor_arg to the front of sk_buff.
From: Ian Campbell @ 2012-04-11 7:56 UTC (permalink / raw)
To: Alexander Duyck
Cc: netdev@vger.kernel.org, David Miller, Eric Dumazet,
Michael S. Tsirkin, Wei Liu (Intern), xen-devel@lists.xen.org
In-Reply-To: <4F847CF9.3090701@intel.com>
On Tue, 2012-04-10 at 19:33 +0100, Alexander Duyck wrote:
> On 04/10/2012 07:26 AM, Ian Campbell wrote:
> > As of the previous patch we align the end (rather than the start) of the struct
> > to a cache line and so, with 32 and 64 byte cache lines and the shinfo size
> > increase from the next patch, the first 8 bytes of the struct end up on a
> > different cache line to the rest of it so make sure it is something relatively
> > unimportant to avoid hitting an extra cache line on hot operations such as
> > kfree_skb.
> >
> > Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
> > Cc: "David S. Miller" <davem@davemloft.net>
> > Cc: Eric Dumazet <eric.dumazet@gmail.com>
> > ---
> > include/linux/skbuff.h | 15 ++++++++++-----
> > net/core/skbuff.c | 5 ++++-
> > 2 files changed, 14 insertions(+), 6 deletions(-)
> >
> > diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
> > index 0ad6a46..f0ae39c 100644
> > --- a/include/linux/skbuff.h
> > +++ b/include/linux/skbuff.h
> > @@ -265,6 +265,15 @@ struct ubuf_info {
> > * the end of the header data, ie. at skb->end.
> > */
> > struct skb_shared_info {
> > + /* Intermediate layers must ensure that destructor_arg
> > + * remains valid until skb destructor */
> > + void *destructor_arg;
> > +
> > + /*
> > + * Warning: all fields from here until dataref are cleared in
> > + * __alloc_skb()
> > + *
> > + */
> > unsigned char nr_frags;
> > __u8 tx_flags;
> > unsigned short gso_size;
> > @@ -276,14 +285,10 @@ struct skb_shared_info {
> > __be32 ip6_frag_id;
> >
> > /*
> > - * Warning : all fields before dataref are cleared in __alloc_skb()
> > + * Warning: all fields before dataref are cleared in __alloc_skb()
> > */
> > atomic_t dataref;
> >
> > - /* Intermediate layers must ensure that destructor_arg
> > - * remains valid until skb destructor */
> > - void * destructor_arg;
> > -
> > /* must be last field, see pskb_expand_head() */
> > skb_frag_t frags[MAX_SKB_FRAGS];
> > };
> > diff --git a/net/core/skbuff.c b/net/core/skbuff.c
> > index d4e139e..b8a41d6 100644
> > --- a/net/core/skbuff.c
> > +++ b/net/core/skbuff.c
> > @@ -214,7 +214,10 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
> >
> > /* make sure we initialize shinfo sequentially */
> > shinfo = skb_shinfo(skb);
> > - memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
> > +
> > + memset(&shinfo->nr_frags, 0,
> > + offsetof(struct skb_shared_info, dataref)
> > + - offsetof(struct skb_shared_info, nr_frags));
> > atomic_set(&shinfo->dataref, 1);
> > kmemcheck_annotate_variable(shinfo->destructor_arg);
> >
>
> Have you checked this for 32 bit as well as 64? Based on my math your
> next patch will still mess up the memset on 32 bit with the structure
> being split somewhere just in front of hwtstamps.
You mean 32 byte cache lines? If so then yes there is a split half way
through the structure in that case but there's no way all this data
could ever fit in a single 32 byte cache line. Not including the frags
or destructor_arg the region nr_frags up to and including dataref is 36
bytes on 32 bit and 40 bytes on 64 bit. I've not changed anything in
this respect.
If you meant 64 byte cache lines with 32 bit structure sizes then by my
calculations everything from destructor_arg (in fact a bit earlier, from
12 bytes before then) up to and including frag[0] is in the same 64 byte
cache line.
I find the easiest way to check is to use gdb and open code an offsetof
macro.
(gdb) print/d sizeof(struct skb_shared_info) - (unsigned long)&(((struct skb_shared_info *)0)->nr_frags)
$3 = 240
(gdb) print/d sizeof(struct skb_shared_info) - (unsigned long)&(((struct skb_shared_info *)0)->frags[1])
$4 = 192
So given 64 byte cache lines the interesting area starts at 240/64=3.75
cache lines from the (aligned) end and it finishes just before 192/64=3
cache lines from the end, so nr_frags through to frags[0] are therefore
on the same cache line.
Ian.
^ permalink raw reply
* Re: [PATCH 07/10] net: only allow paged fragments with the same destructor to be coalesced.
From: Ian Campbell @ 2012-04-11 7:45 UTC (permalink / raw)
To: Ben Hutchings
Cc: netdev@vger.kernel.org, David Miller, Eric Dumazet,
Michael S. Tsirkin, Wei Liu (Intern), xen-devel@lists.xen.org,
Alexey Kuznetsov, Pekka Savola (ipv6), James Morris,
Hideaki YOSHIFUJI, Patrick McHardy, Michał Mirosław
In-Reply-To: <1334088690.2624.1.camel@bwh-desktop.uk.solarflarecom.com>
On Tue, 2012-04-10 at 21:11 +0100, Ben Hutchings wrote:
> Shouldn't this be folded into the previous change 'net: add support for
> per-paged-fragment destructors'? Maybe it doesn't matter since nothing
> is setting a non-NULL fragment destructor yet.
I keep following exactly the same thought pattern and then ending up
leaving it due to indecision. I'll squash it next time unless anyone
thinks it is worth keeping split out.
Ian.
^ permalink raw reply
* Re: [PATCH] tcp: avoid order-1 allocations on wifi and tx path
From: Eric Dumazet @ 2012-04-11 7:38 UTC (permalink / raw)
To: Marc MERLIN, David Miller
Cc: Larry.Finger-tQ5ms3gMjBLk1uMJSBkQmQ,
bhutchings-s/n/eUQHGBpZroRs9YW3xA,
linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1334125848.5300.2330.camel@edumazet-glaptop>
On Wed, 2012-04-11 at 08:30 +0200, Eric Dumazet wrote:
> Marc Merlin reported many order-1 allocations failures in TX path on its
> wireless setup, that dont make any sense with MTU=1500 network, and non
> SG capable hardware.
>
> After investigation, it turns out TCP uses sk_stream_alloc_skb() and
> used as a convention skb_tailroom(skb) to know how many bytes of data
> payload could be put in this skb (for non SG capable devices)
>
...
>
> Reported-by: Marc MERLIN <marc-xnduUnryOU1AfugRpC6u6w@public.gmane.org>
> Tested-by: Marc MERLIN <marc-xnduUnryOU1AfugRpC6u6w@public.gmane.org>
> Signed-off-by: Eric Dumazet <eric.dumazet-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
David, I forgot to say this should be backported to 3.2 & 3.3
commit 87fb4b7b533073 (net: more accurate skb truesize) did the
placement of skb_shared_info at the end of skb head, so
sk_stream_alloc_skb() had to reserve more room so that tailroom stayed
at MSS
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH] tcp: avoid order-1 allocations on wifi and tx path
From: Eric Dumazet @ 2012-04-11 6:30 UTC (permalink / raw)
To: Marc MERLIN
Cc: David Miller, Larry.Finger-tQ5ms3gMjBLk1uMJSBkQmQ,
bhutchings-s/n/eUQHGBpZroRs9YW3xA,
linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1334122980.5300.2154.camel@edumazet-glaptop>
Marc Merlin reported many order-1 allocations failures in TX path on its
wireless setup, that dont make any sense with MTU=1500 network, and non
SG capable hardware.
After investigation, it turns out TCP uses sk_stream_alloc_skb() and
used as a convention skb_tailroom(skb) to know how many bytes of data
payload could be put in this skb (for non SG capable devices)
Note : these skb used kmalloc-4096 (MTU=1500 + MAX_HEADER +
sizeof(struct skb_shared_info) being above 2048)
Later, mac80211 layer need to add some bytes at the tail of skb
(IEEE80211_ENCRYPT_TAILROOM = 18 bytes) and since no more tailroom is
available has to call pskb_expand_head() and request order-1
allocations.
This patch changes sk_stream_alloc_skb() so that only
sk->sk_prot->max_header bytes of headroom are reserved, and use a new
skb field, avail_size to hold the data payload limit.
This way, order-0 allocations done by TCP stack can leave more than 2 KB
of tailroom and no more allocation is performed in mac80211 layer (or
any layer needing some tailroom)
avail_size is unioned with mark/dropcount, since mark will be set later
in IP stack for output packets. Therefore, skb size is unchanged.
Reported-by: Marc MERLIN <marc-xnduUnryOU1AfugRpC6u6w@public.gmane.org>
Tested-by: Marc MERLIN <marc-xnduUnryOU1AfugRpC6u6w@public.gmane.org>
Signed-off-by: Eric Dumazet <eric.dumazet-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
include/linux/skbuff.h | 13 +++++++++++++
net/ipv4/tcp.c | 8 ++++----
net/ipv4/tcp_output.c | 2 +-
3 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 3337027..70a3f8d 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -481,6 +481,7 @@ struct sk_buff {
union {
__u32 mark;
__u32 dropcount;
+ __u32 avail_size;
};
sk_buff_data_t transport_header;
@@ -1366,6 +1367,18 @@ static inline int skb_tailroom(const struct sk_buff *skb)
}
/**
+ * skb_availroom - bytes at buffer end
+ * @skb: buffer to check
+ *
+ * Return the number of bytes of free space at the tail of an sk_buff
+ * allocated by sk_stream_alloc()
+ */
+static inline int skb_availroom(const struct sk_buff *skb)
+{
+ return skb_is_nonlinear(skb) ? 0 : skb->avail_size - skb->len;
+}
+
+/**
* skb_reserve - adjust headroom
* @skb: buffer to alter
* @len: bytes to move
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 5d54ed3..87f497f 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -701,11 +701,12 @@ struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp)
skb = alloc_skb_fclone(size + sk->sk_prot->max_header, gfp);
if (skb) {
if (sk_wmem_schedule(sk, skb->truesize)) {
+ skb_reserve(skb, sk->sk_prot->max_header);
/*
* Make sure that we have exactly size bytes
* available to the caller, no more, no less.
*/
- skb_reserve(skb, skb_tailroom(skb) - size);
+ skb->avail_size = size;
return skb;
}
__kfree_skb(skb);
@@ -995,10 +996,9 @@ new_segment:
copy = seglen;
/* Where to copy to? */
- if (skb_tailroom(skb) > 0) {
+ if (skb_availroom(skb) > 0) {
/* We have some space in skb head. Superb! */
- if (copy > skb_tailroom(skb))
- copy = skb_tailroom(skb);
+ copy = min_t(int, copy, skb_availroom(skb));
err = skb_add_data_nocache(sk, skb, from, copy);
if (err)
goto do_fault;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 364784a..376b2cf 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2060,7 +2060,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to,
/* Punt if not enough space exists in the first SKB for
* the data in the second
*/
- if (skb->len > skb_tailroom(to))
+ if (skb->len > skb_availroom(to))
break;
if (after(TCP_SKB_CB(skb)->end_seq, tcp_wnd_end(tp)))
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [patch net-next 1/5] team: add support for per-port options
From: Jiri Pirko @ 2012-04-11 5:43 UTC (permalink / raw)
To: David Miller; +Cc: netdev, eric.dumazet
In-Reply-To: <20120410.143356.28893999541977853.davem@davemloft.net>
Tue, Apr 10, 2012 at 08:33:56PM CEST, davem@davemloft.net wrote:
>From: Jiri Pirko <jpirko@redhat.com>
>Date: Tue, 10 Apr 2012 17:15:42 +0200
>
>> @@ -81,7 +81,16 @@ EXPORT_SYMBOL(team_port_set_team_mac);
>> * Options handling
>> *******************/
>>
>> -struct team_option *__team_find_option(struct team *team, const char *opt_name)
>> +struct team_option_inst { /* One for each option instance */
>> + struct list_head list;
>> + struct team_option *option;
>> + struct team_port *port; /* != NULL if per-port */
>> + bool changed;
>> + bool removed;
>> +};
>> +
>
>All this indirection... just simply embed struct team_option into
>struct team_option_inst instead of using a pointer, and allocate a
>full team_option_inst where you currently memdup in the options.
Well the list of options is needed alone. When port is added/removed, this list
gets iterated over and instances are created/deleted. Therefore I put
pointer to option to option instance struct to save memory (and also to
be nicer)
^ permalink raw reply
* [PATCH] net: allow pskb_expand_head() to get maximum tailroom
From: Eric Dumazet @ 2012-04-11 6:08 UTC (permalink / raw)
To: Marc MERLIN
Cc: David Miller, Larry.Finger, bhutchings, linux-wireless, netdev
In-Reply-To: <20120411052733.GA17352@merlins.org>
Marc Merlin reported many order-1 allocations failures in TX path on its
wireless setup, that dont make any sense with MTU=1500 network, and non
SG capable hardware.
Turns out part of the problem comes from pskb_expand_head() not using
ksize() to get exact head size given by kmalloc(). Doing the same thing
than __alloc_skb() allows more tailroom in skb and can prevent future
reallocations.
As a bonus, struct skb_shared_info becomes cache line aligned.
Reported-by: Marc MERLIN <marc@merlins.org>
Tested-by: Marc MERLIN <marc@merlins.org>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
net/core/skbuff.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index baf8d28..e598400 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -952,9 +952,11 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
goto adjust_others;
}
- data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
+ data = kmalloc(size + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)),
+ gfp_mask);
if (!data)
goto nodata;
+ size = SKB_WITH_OVERHEAD(ksize(data));
/* Copy only real data... and, alas, header. This should be
* optimized for the cases when header is void.
^ permalink raw reply related
* Re: [PATCH net-next] rtnetlink & bonding: change args got get_tx_queues
From: Eric Dumazet @ 2012-04-11 5:55 UTC (permalink / raw)
To: Stephen Hemminger
Cc: Ben Hutchings, Jay Vosburgh, Andy Gospodarek, David Miller,
netdev
In-Reply-To: <20120410213443.31fc0784@nehalam.linuxnetplumber.net>
On Tue, 2012-04-10 at 21:34 -0700, Stephen Hemminger wrote:
> Change get_tx_queues, drop unsused arg/return value real_tx_queues,
> and use return by value (with error) rather than call by reference.
>
> Probably bonding should just change to LLTX and the whole get_tx_queues
> API could disappear!
Absolutely ;)
^ permalink raw reply
* [PATCH] net: WIZnet drivers: fix possible NULL dereference
From: Mike Sinkovsky @ 2012-04-11 5:53 UTC (permalink / raw)
To: netdev, dan.carpenter, davem; +Cc: Mike Sinkovsky
In-Reply-To: <20120410084006.GA27006@elgon.mountain>
This fixes possible null dereference in probe() function: when both
.mac_addr and .link_gpio are unknown, dev.platform_data may be NULL
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Mike Sinkovsky <msink@permonline.ru>
---
drivers/net/ethernet/wiznet/w5100.c | 2 +-
drivers/net/ethernet/wiznet/w5300.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/wiznet/w5100.c b/drivers/net/ethernet/wiznet/w5100.c
index c28e1d5..157d2f0 100644
--- a/drivers/net/ethernet/wiznet/w5100.c
+++ b/drivers/net/ethernet/wiznet/w5100.c
@@ -682,7 +682,7 @@ static int __devinit w5100_hw_probe(struct platform_device *pdev)
return ret;
priv->irq = irq;
- priv->link_gpio = data->link_gpio;
+ priv->link_gpio = data ? data->link_gpio : -EINVAL;
if (gpio_is_valid(priv->link_gpio)) {
char *link_name = devm_kzalloc(&pdev->dev, 16, GFP_KERNEL);
if (!link_name)
diff --git a/drivers/net/ethernet/wiznet/w5300.c b/drivers/net/ethernet/wiznet/w5300.c
index 88afde9..86d07bb 100644
--- a/drivers/net/ethernet/wiznet/w5300.c
+++ b/drivers/net/ethernet/wiznet/w5300.c
@@ -596,7 +596,7 @@ static int __devinit w5300_hw_probe(struct platform_device *pdev)
return ret;
priv->irq = irq;
- priv->link_gpio = data->link_gpio;
+ priv->link_gpio = data ? data->link_gpio : -EINVAL;
if (gpio_is_valid(priv->link_gpio)) {
char *link_name = devm_kzalloc(&pdev->dev, 16, GFP_KERNEL);
if (!link_name)
--
1.6.3.3
^ permalink raw reply related
* Re: 3.2.8/amd64 full interrupt hangs and deadlocks under big network copies (page allocation failure)
From: Eric Dumazet @ 2012-04-11 5:43 UTC (permalink / raw)
To: Marc MERLIN
Cc: David Miller, Larry.Finger-tQ5ms3gMjBLk1uMJSBkQmQ,
bhutchings-s/n/eUQHGBpZroRs9YW3xA,
linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20120411052733.GA17352-xnduUnryOU1AfugRpC6u6w@public.gmane.org>
On Tue, 2012-04-10 at 22:27 -0700, Marc MERLIN wrote:
> On Tue, Apr 10, 2012 at 08:11:03AM +0200, Eric Dumazet wrote:
> > Please try following patch, as it solved the problem for me (no more
> > order-1 allocations in tx path)
>
> I applied our patch to 3.3.1 and cannot reproduce the problem anymore.
>
> I'll leave a big wireless copy running overnight just in case, but I think
> you fixed it.
>
> Thanks much,
> Marc
Thanks Marc for bringing this issue.
I have a lenovo T420s laptop and could debug the thing pretty fast.
I'll send two official patches.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: 3.2.8/amd64 full interrupt hangs and deadlocks under big network copies (page allocation failure)
From: Marc MERLIN @ 2012-04-11 5:27 UTC (permalink / raw)
To: Eric Dumazet
Cc: David Miller, Larry.Finger, bhutchings, linux-wireless, netdev
In-Reply-To: <1334038263.2907.1.camel@edumazet-glaptop>
On Tue, Apr 10, 2012 at 08:11:03AM +0200, Eric Dumazet wrote:
> Please try following patch, as it solved the problem for me (no more
> order-1 allocations in tx path)
I applied our patch to 3.3.1 and cannot reproduce the problem anymore.
I'll leave a big wireless copy running overnight just in case, but I think
you fixed it.
Thanks much,
Marc
--
"A mouse is a device used to point at the xterm you want to type in" - A.S.R.
Microsoft is to operating systems ....
.... what McDonalds is to gourmet cooking
Home page: http://marc.merlins.org/
^ permalink raw reply
* [PATCH net-next] rtnetlink & bonding: change args got get_tx_queues
From: Stephen Hemminger @ 2012-04-11 4:34 UTC (permalink / raw)
To: Ben Hutchings, Jay Vosburgh, Andy Gospodarek; +Cc: David Miller, netdev
In-Reply-To: <1334009344.7150.268.camel@deadeye>
Change get_tx_queues, drop unsused arg/return value real_tx_queues,
and use return by value (with error) rather than call by reference.
Probably bonding should just change to LLTX and the whole get_tx_queues
API could disappear!
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
drivers/net/bonding/bond_main.c | 7 ++-----
include/net/rtnetlink.h | 5 ++---
net/core/rtnetlink.c | 8 ++++----
3 files changed, 8 insertions(+), 12 deletions(-)
--- a/drivers/net/bonding/bond_main.c 2012-04-09 11:18:09.109148332 -0700
+++ b/drivers/net/bonding/bond_main.c 2012-04-10 21:23:07.380267810 -0700
@@ -4779,12 +4779,9 @@ static int bond_validate(struct nlattr *
return 0;
}
-static int bond_get_tx_queues(struct net *net, struct nlattr *tb[],
- unsigned int *num_queues,
- unsigned int *real_num_queues)
+static int bond_get_tx_queues(struct net *net, const struct nlattr *tb[])
{
- *num_queues = tx_queues;
- return 0;
+ return tx_queues;
}
static struct rtnl_link_ops bond_link_ops __read_mostly = {
--- a/include/net/rtnetlink.h 2012-04-10 21:19:01.369508395 -0700
+++ b/include/net/rtnetlink.h 2012-04-10 21:24:57.897506149 -0700
@@ -77,9 +77,8 @@ struct rtnl_link_ops {
size_t (*get_xstats_size)(const struct net_device *dev);
int (*fill_xstats)(struct sk_buff *skb,
const struct net_device *dev);
- int (*get_tx_queues)(struct net *net, struct nlattr *tb[],
- unsigned int *tx_queues,
- unsigned int *real_tx_queues);
+ int (*get_tx_queues)(struct net *net,
+ const struct nlattr *tb[]);
};
extern int __rtnl_link_register(struct rtnl_link_ops *ops);
--- a/net/core/rtnetlink.c 2012-04-09 11:18:09.673154299 -0700
+++ b/net/core/rtnetlink.c 2012-04-10 21:20:42.002637653 -0700
@@ -1641,14 +1641,14 @@ struct net_device *rtnl_create_link(stru
int err;
struct net_device *dev;
unsigned int num_queues = 1;
- unsigned int real_num_queues = 1;
if (ops->get_tx_queues) {
- err = ops->get_tx_queues(src_net, tb, &num_queues,
- &real_num_queues);
- if (err)
+ err = ops->get_tx_queues(src_net, tb);
+ if (err < 0)
goto err;
+ num_queues = err;
}
+
err = -ENOMEM;
dev = alloc_netdev_mq(ops->priv_size, ifname, ops->setup, num_queues);
if (!dev)
^ permalink raw reply
* [PATCH] rtnetlink: fix comments
From: Stephen Hemminger @ 2012-04-11 4:32 UTC (permalink / raw)
To: Ben Hutchings; +Cc: David Miller, netdev
In-Reply-To: <1334009344.7150.268.camel@deadeye>
Fix spelling and references in rtnetlink.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
v2 - fix bogus comment on get_link_af_size and add get_tx_queues
--- a/include/net/rtnetlink.h 2012-02-27 08:43:02.400935781 -0800
+++ b/include/net/rtnetlink.h 2012-04-10 21:19:01.369508395 -0700
@@ -41,9 +41,11 @@ static inline int rtnl_msg_family(const
* @get_size: Function to calculate required room for dumping device
* specific netlink attributes
* @fill_info: Function to dump device specific netlink attributes
- * @get_xstats_size: Function to calculate required room for dumping devic
+ * @get_xstats_size: Function to calculate required room for dumping device
* specific statistics
* @fill_xstats: Function to dump device specific statistics
+ * @get_tx_queues: Function to determine number of transmit queues to create when
+ * creating a new device.
*/
struct rtnl_link_ops {
struct list_head list;
@@ -94,7 +96,7 @@ extern void rtnl_link_unregister(struct
* @fill_link_af: Function to fill IFLA_AF_SPEC with address family
* specific netlink attributes.
* @get_link_af_size: Function to calculate size of address family specific
- * netlink attributes exlusive the container attribute.
+ * netlink attributes.
* @validate_link_af: Validate a IFLA_AF_SPEC attribute, must check attr
* for invalid configuration settings.
* @set_link_af: Function to parse a IFLA_AF_SPEC attribute and modify
^ permalink raw reply
* Re: [net-next PATCH v1 3/7] net: add fdb generic dump routine
From: Ben Hutchings @ 2012-04-11 3:45 UTC (permalink / raw)
To: John Fastabend
Cc: roprabhu, mst, stephen.hemminger, davem, hadi, jeffrey.t.kirsher,
netdev, gregory.v.rose, krkumar2, sri
In-Reply-To: <20120409220030.3288.31389.stgit@jf-dev1-dcblab>
On Mon, 2012-04-09 at 15:00 -0700, John Fastabend wrote:
> This adds a generic dump routine drivers can call. It
> should be sufficient to handle any bridging model that
> uses the unicast address list. This should be most SR-IOV
> enabled NICs.
[...]
> +static int nlmsg_populate_fdb(struct sk_buff *skb,
> + struct netlink_callback *cb,
> + struct net_device *dev,
> + int *idx,
> + struct netdev_hw_addr_list *list)
> +{
> + struct netdev_hw_addr *ha;
> + struct ndmsg *ndm;
> + struct nlmsghdr *nlh;
> + u32 pid, seq;
> +
> + pid = NETLINK_CB(cb->skb).pid;
> + seq = cb->nlh->nlmsg_seq;
> +
> + list_for_each_entry(ha, &list->list, list) {
> + if (*idx < cb->args[0])
> + goto skip;
> +
> + nlh = nlmsg_put(skb, pid, seq,
> + RTM_NEWNEIGH, sizeof(*ndm), NLM_F_MULTI);
> + if (!nlh)
> + break;
This break is effectively return 0, but shouldn't we return an error?
In practice this does no harm because any subsequent invocation of
nlmsg_populate_fdb() for the same skb is also going to fail here with no
change to *idx. But it would be more obviously correct to return an
error.
[...]
> + }
> + return 0;
> +nla_put_failure:
> + nlmsg_cancel(skb, nlh);
> + return -ENOMEM;
> +}
[...]
--
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: [net-next PATCH v1 2/7] net: addr_list: add exclusive dev_uc_add and dev_mc_add
From: Ben Hutchings @ 2012-04-11 3:33 UTC (permalink / raw)
To: John Fastabend
Cc: roprabhu, mst, stephen.hemminger, davem, hadi, jeffrey.t.kirsher,
netdev, gregory.v.rose, krkumar2, sri
In-Reply-To: <20120409220023.3288.59939.stgit@jf-dev1-dcblab>
On Mon, 2012-04-09 at 15:00 -0700, John Fastabend wrote:
> This adds a dev_uc_add_excl() and dev_mc_add_excl() calls
> similar to the original dev_{uc|mc}_add() except it sets
> the global bit and returns -EEXIST for duplicat entires.
>
> This is useful for drivers that support SR-IOV, macvlan
> devices and any other devices that need to manage the
> unicast and multicast lists.
[...]
> +/**
> + * dev_mc_add_excl - Add a global secondary multicast address
> + * @dev: device
> + * @addr: address to add
> + */
> +int dev_mc_add_excl(struct net_device *dev, unsigned char *addr)
> +{
> + struct netdev_hw_addr *ha;
> + int err;
> +
> + netif_addr_lock_bh(dev);
> + list_for_each_entry(ha, &dev->mc.list, list) {
> + if (!memcmp(ha->addr, addr, dev->addr_len) &&
> + ha->type == NETDEV_HW_ADDR_T_UNICAST) {
> + err = -EEXIST;
> + goto out;
> + }
> + }
> + err = __hw_addr_create_ex(&dev->mc, addr, dev->addr_len,
> + NETDEV_HW_ADDR_T_UNICAST, true);
[...]
The address types are wrong. But do we even need this function yet?
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: [net-next PATCH v1 1/7] net: add generic PF_BRIDGE:RTM_ FDB hooks
From: Ben Hutchings @ 2012-04-11 3:23 UTC (permalink / raw)
To: John Fastabend
Cc: roprabhu, mst, stephen.hemminger, davem, hadi, jeffrey.t.kirsher,
netdev, gregory.v.rose, krkumar2, sri
In-Reply-To: <20120409220017.3288.13746.stgit@jf-dev1-dcblab>
On Mon, 2012-04-09 at 15:00 -0700, John Fastabend wrote:
[...]
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index 1f77540..05822e5 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
[...]
> @@ -905,6 +906,19 @@ struct netdev_fcoe_hbainfo {
> * feature set might be less than what was returned by ndo_fix_features()).
> * Must return >0 or -errno if it changed dev->features itself.
> *
> + * int (*ndo_fdb_add)(struct ndmsg *ndm, struct net_device *dev,
> + * unsigned char *addr, u16 flags)
> + * Adds an FDB entry to dev for addr. The ndmsg contains flags to indicate
> + * if the dev->master FDB should be updated or the devices internal FDB.
I don't think the second sentence is helpful, as rtnl_fdb_add() will
take care of those flags.
> + * int (*ndo_fdb_del)(struct ndmsg *ndm, struct net_device *dev,
> + * unsigned char *addr)
> + * Deletes the FDB entry from dev coresponding to addr. The ndmsg
> + * contains flags to indicate if the dev->master FDB should be
> + * updated or the devices internal FDB.
Similarly here.
> + * int (*ndo_fdb_dump)(struct sk_buff *skb, struct netlink_callback *cb,
> + * struct net_device *dev, int idx)
> + * Used to add FDB entries to dump requests. Implementers should add
> + * entries to skb and update idx with the number of entries.
> */
[...
> --- a/net/core/rtnetlink.c
> +++ b/net/core/rtnetlink.c
[...]
> +static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
> +{
[...]
> + err = -EOPNOTSUPP;
So if NTF_MASTER and NTF_SELF are both set, we can quietly fall back to
just setting one FDB? Not sure that's really desirable though
> + /* Support fdb on master device the net/bridge default case */
> + if ((!ndm->ndm_flags || ndm->ndm_flags & NTF_MASTER) &&
> + (dev->priv_flags & IFF_BRIDGE_PORT)) {
> + struct net_device *master = dev->master;
> +
> + if (master->netdev_ops->ndo_fdb_add)
This operation is surely going to be mandatory for bridge devices, so
this check should be omitted or changed to a BUG_ON().
> + err = master->netdev_ops->ndo_fdb_add(ndm, dev, addr,
> + nlh->nlmsg_flags);
Shoudn't we return early on error?
> + }
> +
> + /* Embedded bridge, macvlan, and any other device support */
> + if ((ndm->ndm_flags & NTF_SELF) &&
> + dev->netdev_ops->ndo_fdb_add)
Error if !dev->netdev_ops->ndo_fdb_add.
> + err = dev->netdev_ops->ndo_fdb_add(ndm, dev, addr,
> + nlh->nlmsg_flags);
Wonder what we should do on error here if we've already successfully
called ndo_fdb_add on the master? Should we try to roll back the first
addition?
> + return err;
> +}
> +
> +static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
> +{
[...]
> + err = -EOPNOTSUPP;
> +
> + /* Support fdb on master device the net/bridge default case */
> + if ((!ndm->ndm_flags || ndm->ndm_flags & NTF_MASTER) &&
> + (dev->priv_flags & IFF_BRIDGE_PORT)) {
> + struct net_device *master = dev->master;
> +
> + if (master->netdev_ops->ndo_fdb_del)
> + err = master->netdev_ops->ndo_fdb_del(ndm, dev, addr);
> + }
> +
> + /* Embedded bridge, macvlan, and any other device support */
> + if ((ndm->ndm_flags & NTF_SELF) &&
> + dev->netdev_ops->ndo_fdb_del)
> + err = dev->netdev_ops->ndo_fdb_del(ndm, dev, addr);
> + return err;
> +}
[...]
This has the same issues.
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: [PATCH v15 04/13] arch/x86: add syscall_get_arch to syscall.h
From: H. Peter Anvin @ 2012-04-11 3:20 UTC (permalink / raw)
To: Will Drewry
Cc: linux-kernel, linux-arch, linux-doc, kernel-hardening, netdev,
x86, arnd, davem, mingo, oleg, peterz, rdunlap, mcgrathr, tglx,
luto, eparis, serge.hallyn, djm, scarybeasts, indan, pmoore, akpm,
corbet, eric.dumazet, markus, coreyb, keescook
In-Reply-To: <CABqD9hZgnrKFY_Wei-ysU=Dy7Og2iEemnqPvcQ14M0+vL65gHQ@mail.gmail.com>
On 04/10/2012 08:13 PM, Will Drewry wrote:
> On Sun, Mar 25, 2012 at 2:34 PM, H. Peter Anvin <hpa@zytor.com> wrote:
>> On 03/14/2012 08:11 PM, Will Drewry wrote:
>>>
>>> +static inline int syscall_get_arch(struct task_struct *task,
>>> + struct pt_regs *regs)
>>> +{
>>> +#ifdef CONFIG_IA32_EMULATION
>>> + /*
>>> + * TS_COMPAT is set for 32-bit syscall entries and then
>>> + * remains set until we return to user mode.
>>> + *
>>> + * TIF_IA32 tasks should always have TS_COMPAT set at
>>> + * system call time.
>>> + */
>>> + if (task_thread_info(task)->status & TS_COMPAT)
>>> + return AUDIT_ARCH_I386;
>>> +#endif
>>> + return AUDIT_ARCH_X86_64;
>>> +}
>>> #endif /* CONFIG_X86_32 */
>>>
>>> #endif /* _ASM_X86_SYSCALL_H */
>>
>> Just one FYI on this: after the x32 changes are upstream this can be
>> implemented in terms of is_ia32_task().
>
> Now that I've seen is_ia32_task(), it appears to be exactly the same as above:
> (1) If we're x86_32, it's ia32
> (2) If we're x86_64, ia32 == !!(status & TS_COMPAT)
> (3) Otherwise, it's x86_64, including x32
>
> Am I missing something? Should is_ia32_task(void) take a task_struct?
> Right now, I don't see any reason to change the code, as posted, but
> maybe I am mis-reading?
>
Sorry, answered the wrong question. Yes, it is the same as above...
just wandered if we could centralize this test. It might indeed make
sense to provide general predicates which take a task pointer.
-hpa
^ permalink raw reply
* Re: [PATCH v15 04/13] arch/x86: add syscall_get_arch to syscall.h
From: H. Peter Anvin @ 2012-04-11 3:16 UTC (permalink / raw)
To: Will Drewry
Cc: linux-kernel, linux-arch, linux-doc, kernel-hardening, netdev,
x86, arnd, davem, mingo, oleg, peterz, rdunlap, mcgrathr, tglx,
luto, eparis, serge.hallyn, djm, scarybeasts, indan, pmoore, akpm,
corbet, eric.dumazet, markus, coreyb, keescook
In-Reply-To: <CABqD9hZgnrKFY_Wei-ysU=Dy7Og2iEemnqPvcQ14M0+vL65gHQ@mail.gmail.com>
On 04/10/2012 08:13 PM, Will Drewry wrote:
>
> Now that I've seen is_ia32_task(), it appears to be exactly the same as above:
> (1) If we're x86_32, it's ia32
> (2) If we're x86_64, ia32 == !!(status & TS_COMPAT)
> (3) Otherwise, it's x86_64, including x32
>
> Am I missing something? Should is_ia32_task(void) take a task_struct?
> Right now, I don't see any reason to change the code, as posted, but
> maybe I am mis-reading?
>
is_compat_task() is true for x32, is_ia32_task() is false.
-hpa
^ permalink raw reply
* Re: [PATCH v15 04/13] arch/x86: add syscall_get_arch to syscall.h
From: Will Drewry @ 2012-04-11 3:13 UTC (permalink / raw)
To: H. Peter Anvin
Cc: linux-kernel, linux-arch, linux-doc, kernel-hardening, netdev,
x86, arnd, davem, mingo, oleg, peterz, rdunlap, mcgrathr, tglx,
luto, eparis, serge.hallyn, djm, scarybeasts, indan, pmoore, akpm,
corbet, eric.dumazet, markus, coreyb, keescook
In-Reply-To: <4F6F7362.6030402@zytor.com>
On Sun, Mar 25, 2012 at 2:34 PM, H. Peter Anvin <hpa@zytor.com> wrote:
> On 03/14/2012 08:11 PM, Will Drewry wrote:
>>
>> +static inline int syscall_get_arch(struct task_struct *task,
>> + struct pt_regs *regs)
>> +{
>> +#ifdef CONFIG_IA32_EMULATION
>> + /*
>> + * TS_COMPAT is set for 32-bit syscall entries and then
>> + * remains set until we return to user mode.
>> + *
>> + * TIF_IA32 tasks should always have TS_COMPAT set at
>> + * system call time.
>> + */
>> + if (task_thread_info(task)->status & TS_COMPAT)
>> + return AUDIT_ARCH_I386;
>> +#endif
>> + return AUDIT_ARCH_X86_64;
>> +}
>> #endif /* CONFIG_X86_32 */
>>
>> #endif /* _ASM_X86_SYSCALL_H */
>
> Just one FYI on this: after the x32 changes are upstream this can be
> implemented in terms of is_ia32_task().
Now that I've seen is_ia32_task(), it appears to be exactly the same as above:
(1) If we're x86_32, it's ia32
(2) If we're x86_64, ia32 == !!(status & TS_COMPAT)
(3) Otherwise, it's x86_64, including x32
Am I missing something? Should is_ia32_task(void) take a task_struct?
Right now, I don't see any reason to change the code, as posted, but
maybe I am mis-reading?
thanks!
will
^ permalink raw reply
* RE: Expose ltr/obff interface by sysfs
From: Hao, Xudong @ 2012-04-11 3:02 UTC (permalink / raw)
To: Konrad Rzeszutek Wilk
Cc: linux-pci@vger.kernel.org, netdev@vger.kernel.org,
e1000-devel@lists.sourceforge.net, Jesse Barnes
In-Reply-To: <20120406183932.GB13473@phenom.dumpdata.com>
> But a better question is - why should this be done - especially from the guest
> which has a limited view of the machine? The machine might be running a lot of
> other requests so the OBFF inside the guest could be invalid.
>
Maybe I did not describe it clearly, the original idea is host admin can control the inode interface but not guest.
> -----Original Message-----
> From: Konrad Rzeszutek Wilk [mailto:konrad.wilk@oracle.com]
> Sent: Saturday, April 07, 2012 2:40 AM
> To: Hao, Xudong
> Cc: linux-pci@vger.kernel.org; netdev@vger.kernel.org;
> e1000-devel@lists.sourceforge.net; Jesse Barnes
> Subject: Re: Expose ltr/obff interface by sysfs
>
> On Fri, Apr 06, 2012 at 02:43:59AM +0000, Hao, Xudong wrote:
> > Hi,
> >
> > I'm working on virtualization Xen/KVM. I saw there are ltr/obff
> enabling/disabling function in pci.c, but no called till now. I want to know if
> anybody(driver developer) are working for using it? Can driver change the LTR
> latency value dynamically?
> >
> > /*
> > LTR(Latency tolerance reporting) allows devices to send messages to the root
> complex indicating their latency tolerance for snooped & unsnooped memory
> transactions.
> > OBFF (optimized buffer flush/fill), where supported, can help improve energy
> efficiency by giving devices information about when interrupts and other
> activity will have a reduced power impact.
> > */
> >
> > One way to control ltr/obff is used by driver, however, I'm considering that in
> virtualization, how guest OS driver control them. I have an idea that expose an
> inode interface by sysfs, like "reset" inode implemented in pci-sysfs.c, so that
> system user/administrator can enable/disable ltr/obff or set latency value on
> userspace, but not limited on driver. Comments?
>
> So right now the driver inside the guest can probably see it, but can't change
> them.
> (As those requests end up being filtered).
>
> But there is nothing wrong with your changing those values from within the
> host.
>
> But a better question is - why should this be done - especially from the guest
> which has a limited view of the machine? The machine might be running a lot of
> other requests so the OBFF inside the guest could be invalid.
>
>
> >
> > < pls CC me when reply this mail, thanks >
> >
> > Best Regards,
> > Xudong Hao
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-pci"
> > 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
* linux-next: manual merge of the wireless-next tree with the net-next tree
From: Stephen Rothwell @ 2012-04-11 2:56 UTC (permalink / raw)
To: John W. Linville
Cc: linux-next, linux-kernel, David Miller, netdev, Javier Cardona,
Marco Porsch, Pavel Zubarev
[-- Attachment #1: Type: text/plain, Size: 6481 bytes --]
Hi John,
Today's linux-next merge of the wireless-next tree got a conflict in
net/wireless/nl80211.c between commit 9360ffd18597 ("wireless: Stop using
NLA_PUT*()") from the net-next tree and commit d299a1f21ea7 ("{nl,cfg}
80211: Support for mesh synchronization") from the wireless-next tree.
I fixed it up (see below) and can carry the fix as necessary.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
diff --cc net/wireless/nl80211.c
index 65622e9,b12a052..0000000
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@@ -2540,17 -2486,18 +2543,20 @@@ static int nl80211_send_station(struct
nla_nest_end(msg, bss_param);
}
- if (sinfo->filled & STATION_INFO_STA_FLAGS)
- NLA_PUT(msg, NL80211_STA_INFO_STA_FLAGS,
- sizeof(struct nl80211_sta_flag_update),
- &sinfo->sta_flags);
- if (sinfo->filled & STATION_INFO_T_OFFSET)
- NLA_PUT_U64(msg, NL80211_STA_INFO_T_OFFSET,
- sinfo->t_offset);
+ if ((sinfo->filled & STATION_INFO_STA_FLAGS) &&
+ nla_put(msg, NL80211_STA_INFO_STA_FLAGS,
+ sizeof(struct nl80211_sta_flag_update),
+ &sinfo->sta_flags))
+ goto nla_put_failure;
++ if ((sinfo->filled & STATION_INFO_T_OFFSET) &&
++ nla_put_u64(msg, NL80211_STA_INFO_T_OFFSET, sinfo->t_offset))
++ goto nla_put_failure;
nla_nest_end(msg, sinfoattr);
- if (sinfo->filled & STATION_INFO_ASSOC_REQ_IES)
- NLA_PUT(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
- sinfo->assoc_req_ies);
+ if ((sinfo->filled & STATION_INFO_ASSOC_REQ_IES) &&
+ nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
+ sinfo->assoc_req_ies))
+ goto nla_put_failure;
return genlmsg_end(msg, hdr);
@@@ -3328,48 -3274,49 +3334,50 @@@ static int nl80211_get_mesh_config(stru
pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
if (!pinfoattr)
goto nla_put_failure;
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
- NLA_PUT_U16(msg, NL80211_MESHCONF_RETRY_TIMEOUT,
- cur_params.dot11MeshRetryTimeout);
- NLA_PUT_U16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT,
- cur_params.dot11MeshConfirmTimeout);
- NLA_PUT_U16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT,
- cur_params.dot11MeshHoldingTimeout);
- NLA_PUT_U16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
- cur_params.dot11MeshMaxPeerLinks);
- NLA_PUT_U8(msg, NL80211_MESHCONF_MAX_RETRIES,
- cur_params.dot11MeshMaxRetries);
- NLA_PUT_U8(msg, NL80211_MESHCONF_TTL,
- cur_params.dot11MeshTTL);
- NLA_PUT_U8(msg, NL80211_MESHCONF_ELEMENT_TTL,
- cur_params.element_ttl);
- NLA_PUT_U8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
- cur_params.auto_open_plinks);
- NLA_PUT_U32(msg, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
- cur_params.dot11MeshNbrOffsetMaxNeighbor);
- NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
- cur_params.dot11MeshHWMPmaxPREQretries);
- NLA_PUT_U32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME,
- cur_params.path_refresh_time);
- NLA_PUT_U16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
- cur_params.min_discovery_timeout);
- NLA_PUT_U32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
- cur_params.dot11MeshHWMPactivePathTimeout);
- NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
- cur_params.dot11MeshHWMPpreqMinInterval);
- NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
- cur_params.dot11MeshHWMPperrMinInterval);
- NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
- cur_params.dot11MeshHWMPnetDiameterTraversalTime);
- NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
- cur_params.dot11MeshHWMPRootMode);
- NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
- cur_params.dot11MeshHWMPRannInterval);
- NLA_PUT_U8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
- cur_params.dot11MeshGateAnnouncementProtocol);
- NLA_PUT_U8(msg, NL80211_MESHCONF_FORWARDING,
- cur_params.dot11MeshForwarding);
- NLA_PUT_U32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
- cur_params.rssi_threshold);
+ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
+ nla_put_u16(msg, NL80211_MESHCONF_RETRY_TIMEOUT,
+ cur_params.dot11MeshRetryTimeout) ||
+ nla_put_u16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT,
+ cur_params.dot11MeshConfirmTimeout) ||
+ nla_put_u16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT,
+ cur_params.dot11MeshHoldingTimeout) ||
+ nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
+ cur_params.dot11MeshMaxPeerLinks) ||
+ nla_put_u8(msg, NL80211_MESHCONF_MAX_RETRIES,
+ cur_params.dot11MeshMaxRetries) ||
+ nla_put_u8(msg, NL80211_MESHCONF_TTL,
+ cur_params.dot11MeshTTL) ||
+ nla_put_u8(msg, NL80211_MESHCONF_ELEMENT_TTL,
+ cur_params.element_ttl) ||
+ nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+ cur_params.auto_open_plinks) ||
++ nla_put_u32(msg, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
++ cur_params.dot11MeshNbrOffsetMaxNeighbor) ||
+ nla_put_u8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
+ cur_params.dot11MeshHWMPmaxPREQretries) ||
+ nla_put_u32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME,
+ cur_params.path_refresh_time) ||
+ nla_put_u16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
+ cur_params.min_discovery_timeout) ||
+ nla_put_u32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
+ cur_params.dot11MeshHWMPactivePathTimeout) ||
+ nla_put_u16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
+ cur_params.dot11MeshHWMPpreqMinInterval) ||
+ nla_put_u16(msg, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
+ cur_params.dot11MeshHWMPperrMinInterval) ||
+ nla_put_u16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
+ cur_params.dot11MeshHWMPnetDiameterTraversalTime) ||
+ nla_put_u8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
+ cur_params.dot11MeshHWMPRootMode) ||
+ nla_put_u16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+ cur_params.dot11MeshHWMPRannInterval) ||
+ nla_put_u8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
+ cur_params.dot11MeshGateAnnouncementProtocol) ||
+ nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
+ cur_params.dot11MeshForwarding) ||
+ nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
+ cur_params.rssi_threshold))
+ goto nla_put_failure;
nla_nest_end(msg, pinfoattr);
genlmsg_end(msg, hdr);
return genlmsg_reply(msg, info);
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH] memcg/tcp: fix warning caused b res->usage go to negative.
From: Glauber Costa @ 2012-04-11 2:22 UTC (permalink / raw)
To: KAMEZAWA Hiroyuki; +Cc: netdev, David Miller, Andrew Morton
In-Reply-To: <4F83B3FD.4010107@jp.fujitsu.com>
>
> The problem is that jump_label updating is not atomic_ops.
That's indeed really bad.
You seem to be right about that... I wonder, however, if we should
prevent anything to run in any cpu during the jump_label update?
The update can be slow, sure, but it is not expected to be frequent...
> I'm _not_ sure the update order of the jump_label in sock_update_memcg()
> and other jump instructions inserted at accounting.
Any ordering assumptions here would be extremely fragile, even if we
could make one.
> For example, if the jump instruction in sock_update_memcg() is updated 1st
> and others are updated later, it's unclear whether sockets which has _valid_
> sock->sk_cgrp will be accounted or not because accounting jump instruction
> may not be updated yet.
>
> Hopefully, label in sock_update_memcg should be updated last...
>
> Hm. If I do, I'll add one more key as:
>
> atomic_t sock_should_memcg_aware;
>
> And update 2 keys in following order.
>
> At enable
> static_key_slow_inc(&memcg_socket_limit_enabled)
> atomic_inc(&sock_should_memcg_aware);
>
> At disable
> atomic_dec(&sock_should_memcg_aware);
> static_key_slow_dec(&memcg_socket_limit_enabled)
>
> And
> ==
> void sock_update_memcg(struct sock *sk)
> {
> if (atomic_read(&sock_should_memcg_aware)) {
>
> ==
Problem here is that having an atomic variable here defeats a bit the
purpose of the jump labels.
If it is just in the update path, it is not *that* bad.
But unless we go fix the jump labels to prevent such thing from
happening, maybe it would be better to have two jump labels here?
One for the writer, that is updated last, and one from the readers.
This way we can force the ordering the way we want.
^ permalink raw reply
* [net-next PATCH 2/2] net/l2tp: add support for L2TP over IPv6 UDP
From: Benjamin LaHaise @ 2012-04-11 2:21 UTC (permalink / raw)
To: David S. Miller, James Chapman; +Cc: netdev
This patch adds support for carrying L2TP frames over UDP on top of IPv6 in
addition to the existing UDP on IPv4. Support has been tested with both hw
accelerated ethernet drivers, as well as dumb interfaces.
Signed-off-by: Benjamin LaHaise <bcrl@kvack.org>
---
include/linux/if_pppol2tp.h | 28 ++++++++++++++-
include/linux/if_pppox.h | 12 ++++++
net/l2tp/l2tp_core.c | 84 ++++++++++++++++++++++++++++++++++++------
net/l2tp/l2tp_ppp.c | 42 +++++++++++++++++++++-
4 files changed, 152 insertions(+), 14 deletions(-)
diff --git a/include/linux/if_pppol2tp.h b/include/linux/if_pppol2tp.h
index 23cefa1..b477541 100644
--- a/include/linux/if_pppol2tp.h
+++ b/include/linux/if_pppol2tp.h
@@ -19,10 +19,11 @@
#ifdef __KERNEL__
#include <linux/in.h>
+#include <linux/in6.h>
#endif
/* Structure used to connect() the socket to a particular tunnel UDP
- * socket.
+ * socket over IPv4.
*/
struct pppol2tp_addr {
__kernel_pid_t pid; /* pid that owns the fd.
@@ -35,6 +36,20 @@ struct pppol2tp_addr {
__u16 d_tunnel, d_session; /* For sending outgoing packets */
};
+/* Structure used to connect() the socket to a particular tunnel UDP
+ * socket over IPv6.
+ */
+struct pppol2tpin6_addr {
+ __kernel_pid_t pid; /* pid that owns the fd.
+ * 0 => current */
+ int fd; /* FD of UDP socket to use */
+
+ __u16 s_tunnel, s_session; /* For matching incoming packets */
+ __u16 d_tunnel, d_session; /* For sending outgoing packets */
+
+ struct sockaddr_in6 addr; /* IP address and port to send to */
+};
+
/* The L2TPv3 protocol changes tunnel and session ids from 16 to 32
* bits. So we need a different sockaddr structure.
*/
@@ -49,6 +64,17 @@ struct pppol2tpv3_addr {
__u32 d_tunnel, d_session; /* For sending outgoing packets */
};
+struct pppol2tpv3in6_addr {
+ __kernel_pid_t pid; /* pid that owns the fd.
+ * 0 => current */
+ int fd; /* FD of UDP or IP socket to use */
+
+ __u32 s_tunnel, s_session; /* For matching incoming packets */
+ __u32 d_tunnel, d_session; /* For sending outgoing packets */
+
+ struct sockaddr_in6 addr; /* IP address and port to send to */
+};
+
/* Socket options:
* DEBUG - bitmask of debug message categories
* SENDSEQ - 0 => don't send packets with sequence numbers
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
index b5f927f..6720d57 100644
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -83,6 +83,12 @@ struct sockaddr_pppol2tp {
struct pppol2tp_addr pppol2tp;
} __attribute__((packed));
+struct sockaddr_pppol2tpin6 {
+ __kernel_sa_family_t sa_family; /* address family, AF_PPPOX */
+ unsigned int sa_protocol; /* protocol identifier */
+ struct pppol2tpin6_addr pppol2tp;
+} __attribute__((packed));
+
/* The L2TPv3 protocol changes tunnel and session ids from 16 to 32
* bits. So we need a different sockaddr structure.
*/
@@ -92,6 +98,12 @@ struct sockaddr_pppol2tpv3 {
struct pppol2tpv3_addr pppol2tp;
} __attribute__((packed));
+struct sockaddr_pppol2tpv3in6 {
+ __kernel_sa_family_t sa_family; /* address family, AF_PPPOX */
+ unsigned int sa_protocol; /* protocol identifier */
+ struct pppol2tpv3in6_addr pppol2tp;
+} __attribute__((packed));
+
/*********************************************************************
*
* ioctl interface for defining forwarding of connections
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 89ff8c6..ef024a4 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -53,6 +53,9 @@
#include <net/inet_common.h>
#include <net/xfrm.h>
#include <net/protocol.h>
+#include <net/inet6_connection_sock.h>
+#include <net/inet_ecn.h>
+#include <net/ip6_route.h>
#include <asm/byteorder.h>
#include <linux/atomic.h>
@@ -446,21 +449,43 @@ static inline int l2tp_verify_udp_checksum(struct sock *sk,
{
struct udphdr *uh = udp_hdr(skb);
u16 ulen = ntohs(uh->len);
- struct inet_sock *inet;
__wsum psum;
- if (sk->sk_no_check || skb_csum_unnecessary(skb) || !uh->check)
- return 0;
-
- inet = inet_sk(sk);
- psum = csum_tcpudp_nofold(inet->inet_saddr, inet->inet_daddr, ulen,
- IPPROTO_UDP, 0);
-
- if ((skb->ip_summed == CHECKSUM_COMPLETE) &&
- !csum_fold(csum_add(psum, skb->csum)))
+ if (sk->sk_no_check || skb_csum_unnecessary(skb))
return 0;
- skb->csum = psum;
+#if IS_ENABLED(CONFIG_IPV6)
+ if (sk->sk_family == PF_INET6) {
+ if (!uh->check) {
+ LIMIT_NETDEBUG(KERN_INFO "L2TP: IPv6: checksum is 0\n");
+ return 1;
+ }
+ if ((skb->ip_summed == CHECKSUM_COMPLETE) &&
+ !csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr, ulen,
+ IPPROTO_UDP, skb->csum)) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ return 0;
+ }
+ skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr,
+ skb->len, IPPROTO_UDP,
+ 0));
+ } else
+#endif
+ {
+ struct inet_sock *inet;
+ if (!uh->check)
+ return 0;
+ inet = inet_sk(sk);
+ psum = csum_tcpudp_nofold(inet->inet_saddr, inet->inet_daddr,
+ ulen, IPPROTO_UDP, 0);
+
+ if ((skb->ip_summed == CHECKSUM_COMPLETE) &&
+ !csum_fold(csum_add(psum, skb->csum)))
+ return 0;
+ skb->csum = psum;
+ }
return __skb_checksum_complete(skb);
}
@@ -988,7 +1013,12 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb,
/* Queue the packet to IP for output */
skb->local_df = 1;
- error = ip_queue_xmit(skb, fl);
+#if IS_ENABLED(CONFIG_IPV6)
+ if (skb->sk->sk_family == PF_INET6)
+ error = inet6_csk_xmit(skb, NULL);
+ else
+#endif
+ error = ip_queue_xmit(skb, fl);
/* Update stats */
if (error >= 0) {
@@ -1021,6 +1051,31 @@ static inline void l2tp_skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
skb->destructor = l2tp_sock_wfree;
}
+#if IS_ENABLED(CONFIG_IPV6)
+static void l2tp_xmit_ipv6_csum(struct sock *sk, struct sk_buff *skb,
+ int udp_len)
+{
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ struct udphdr *uh = udp_hdr(skb);
+
+ if (!skb_dst(skb) || !skb_dst(skb)->dev ||
+ !(skb_dst(skb)->dev->features & NETIF_F_IPV6_CSUM)) {
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ skb->csum = skb_checksum(skb, 0, udp_len, 0);
+ uh->check = csum_ipv6_magic(&np->saddr, &np->daddr, udp_len,
+ IPPROTO_UDP, skb->csum);
+ if (uh->check == 0)
+ uh->check = CSUM_MANGLED_0;
+ } else {
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ skb->csum_start = skb_transport_header(skb) - skb->head;
+ skb->csum_offset = offsetof(struct udphdr, check);
+ uh->check = ~csum_ipv6_magic(&np->saddr, &np->daddr,
+ udp_len, IPPROTO_UDP, 0);
+ }
+}
+#endif
+
/* If caller requires the skb to have a ppp header, the header must be
* inserted in the skb data before calling this function.
*/
@@ -1089,6 +1144,11 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
uh->check = 0;
/* Calculate UDP checksum if configured to do so */
+#if IS_ENABLED(CONFIG_IPV6)
+ if (sk->sk_family == PF_INET6)
+ l2tp_xmit_ipv6_csum(sk, skb, udp_len);
+ else
+#endif
if (sk->sk_no_check == UDP_CSUM_NOXMIT)
skb->ip_summed = CHECKSUM_NONE;
else if ((skb_dst(skb) && skb_dst(skb)->dev) &&
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 1addd9f..27b9dec 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -916,7 +916,7 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
}
inet = inet_sk(tunnel->sock);
- if (tunnel->version == 2) {
+ if ((tunnel->version == 2) && (tunnel->sock->sk_family == AF_INET)) {
struct sockaddr_pppol2tp sp;
len = sizeof(sp);
memset(&sp, 0, len);
@@ -932,6 +932,46 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
sp.pppol2tp.addr.sin_port = inet->inet_dport;
sp.pppol2tp.addr.sin_addr.s_addr = inet->inet_daddr;
memcpy(uaddr, &sp, len);
+#if IS_ENABLED(CONFIG_IPV6)
+ } else if ((tunnel->version == 2) &&
+ (tunnel->sock->sk_family == AF_INET6)) {
+ struct ipv6_pinfo *np = inet6_sk(tunnel->sock);
+ struct sockaddr_pppol2tpin6 sp;
+ len = sizeof(sp);
+ memset(&sp, 0, len);
+ sp.sa_family = AF_PPPOX;
+ sp.sa_protocol = PX_PROTO_OL2TP;
+ sp.pppol2tp.fd = tunnel->fd;
+ sp.pppol2tp.pid = pls->owner;
+ sp.pppol2tp.s_tunnel = tunnel->tunnel_id;
+ sp.pppol2tp.d_tunnel = tunnel->peer_tunnel_id;
+ sp.pppol2tp.s_session = session->session_id;
+ sp.pppol2tp.d_session = session->peer_session_id;
+ sp.pppol2tp.addr.sin6_family = AF_INET6;
+ sp.pppol2tp.addr.sin6_port = inet->inet_dport;
+ memcpy(&sp.pppol2tp.addr.sin6_addr, &np->daddr,
+ sizeof(np->daddr));
+ memcpy(uaddr, &sp, len);
+ } else if ((tunnel->version == 3) &&
+ (tunnel->sock->sk_family == AF_INET6)) {
+ struct ipv6_pinfo *np = inet6_sk(tunnel->sock);
+ struct sockaddr_pppol2tpv3in6 sp;
+ len = sizeof(sp);
+ memset(&sp, 0, len);
+ sp.sa_family = AF_PPPOX;
+ sp.sa_protocol = PX_PROTO_OL2TP;
+ sp.pppol2tp.fd = tunnel->fd;
+ sp.pppol2tp.pid = pls->owner;
+ sp.pppol2tp.s_tunnel = tunnel->tunnel_id;
+ sp.pppol2tp.d_tunnel = tunnel->peer_tunnel_id;
+ sp.pppol2tp.s_session = session->session_id;
+ sp.pppol2tp.d_session = session->peer_session_id;
+ sp.pppol2tp.addr.sin6_family = AF_INET6;
+ sp.pppol2tp.addr.sin6_port = inet->inet_dport;
+ memcpy(&sp.pppol2tp.addr.sin6_addr, &np->daddr,
+ sizeof(np->daddr));
+ memcpy(uaddr, &sp, len);
+#endif
} else if (tunnel->version == 3) {
struct sockaddr_pppol2tpv3 sp;
len = sizeof(sp);
--
1.7.4.1
--
"Thought is the essence of where you are now."
^ permalink raw reply related
* [PATCH net-next 1/2] net/ipv6/udp: Add encap_rcv support to IPv6 UDP
From: Benjamin LaHaise @ 2012-04-11 2:20 UTC (permalink / raw)
To: David S. Miller, James Chapman; +Cc: netdev
At present, UDP encapsulated protocols (like L2TP) are only able to use the
encap_rcv hook with UDP over IPv4. This patch adds the same support for use
with UDP over IPv6.
Signed-off-by: Benjamin LaHaise <bcrl@kvack.org>
---
net/ipv6/udp.c | 31 +++++++++++++++++++++++++++++++
1 files changed, 31 insertions(+), 0 deletions(-)
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 37b0699..4d7cd72 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -515,6 +515,37 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
goto drop;
+ if (up->encap_type) {
+ int (*encap_rcv)(struct sock *sk, struct sk_buff *skb);
+
+ /*
+ * This is an encapsulation socket so pass the skb to
+ * the socket's udp_encap_rcv() hook. Otherwise, just
+ * fall through and pass this up the UDP socket.
+ * up->encap_rcv() returns the following value:
+ * =0 if skb was successfully passed to the encap
+ * handler or was discarded by it.
+ * >0 if skb should be passed on to UDP.
+ * <0 if skb should be resubmitted as proto -N
+ */
+
+ /* if we're overly short, let UDP handle it */
+ encap_rcv = ACCESS_ONCE(up->encap_rcv);
+ if (skb->len > sizeof(struct udphdr) && encap_rcv != NULL) {
+ int ret;
+
+ ret = encap_rcv(sk, skb);
+ if (ret <= 0) {
+ UDP6_INC_STATS_BH(sock_net(sk),
+ UDP_MIB_INDATAGRAMS,
+ is_udplite);
+ return -ret;
+ }
+ }
+
+ /* FALLTHROUGH -- it's a UDP Packet */
+ }
+
/*
* UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c).
*/
--
1.7.4.1
--
"Thought is the essence of where you are now."
^ permalink raw reply related
* rcu_sched_state detected stall, no stack trace
From: Prashant Batra (prbatra) @ 2012-04-11 2:20 UTC (permalink / raw)
To: netdev
Hi,
I am running vanilla kernel 3.0.23 . I am trying to add some 6K and more
IPv6 IPSec tunnels.
I am getting these warnings in dmesg close to 6k tunnels, after which
the kernel hangs and have to reboot the kernel.
[ 1511.045261] INFO: rcu_sched_state detected stall on CPU 4 (t=300000
jiffies) [ 1534.736899] INFO: rcu_bh_state detected stalls on
CPUs/tasks: { 4} (detected by 13, t=300002 jiffies)
I am not getting any back-trace also, to figure out what is actually
causing the stall to happen.
Could someone help to figure out the issue.
Regards,
Prashant
^ 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