Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH 1/2] dt: introduce for_each_available_child_of_node, of_get_next_available_child
From: David Miller @ 2012-08-20  9:16 UTC (permalink / raw)
  To: timur; +Cc: grant.likely, david.daney, netdev, devicetree-discuss
In-Reply-To: <1344986424-14360-1-git-send-email-timur@freescale.com>

From: Timur Tabi <timur@freescale.com>
Date: Tue, 14 Aug 2012 18:20:23 -0500

> Macro for_each_child_of_node() makes it easy to iterate over all of the
> children for a given device tree node, including those nodes that are
> marked as unavailable (i.e. status = "disabled").
> 
> Introduce for_each_available_child_of_node(), which is like
> for_each_child_of_node(), but it automatically skips unavailable nodes.
> This also requires the introduction of helper function
> of_get_next_available_child(), which returns the next available child
> node.
> 
> Signed-off-by: Timur Tabi <timur@freescale.com>

Applied.

^ permalink raw reply

* Re: [RFC Patch net-next] ipv6: unify conntrack reassembly expire code with standard one
From: Cong Wang @ 2012-08-20  9:06 UTC (permalink / raw)
  To: Michal Kubeček
  Cc: netdev, Herbert Xu, David S. Miller, Hideaki YOSHIFUJI,
	Patrick McHardy, Shan Wei, Pablo Neira Ayuso, netfilter-devel
In-Reply-To: <1826853.rak2U42CMU@alaris>

Hi, Michal!

On Fri, 2012-08-17 at 19:05 +0200, Michal Kubeček wrote:
> On Friday 17 of August 2012 16:02EN, Cong Wang wrote:
> > Two years ago, Shan Wei tried to fix this:
> > http://patchwork.ozlabs.org/patch/43905/
> > 
> ...
> >
> > As Herbert suggested, we could actually use the standard IPv6
> > reassembly code which follows RFC2460.
> 
> I tested the patch and I ran into a problem in this place in 
> ip6_expire_frag_queue():
> 
> >  	net = container_of(fq->q.net, struct net, ipv6.frags);
> 
> For frag queues coming from IPv6 conntrack, fq->q.net points to 
> nf_init_frags which is not embedded into struct net so that the 
> following device lookup leads to reading from an invalid address.
> The same problem has been discussed on the page linked above.
> 
> I didn't test with current net-next source but as far as I can tell, 
> this hasn't changed. Did I miss something?
> 

No, you don't miss anything. I missed that piece of code, you are right
that nf_init_frags is not actually embedded, so that container_of()
doesn't work. I think we probably can save the struct net pointer in
struct netns_frags during inet_frags_init_net(), so that container_of()
can be eliminated. 

Thanks for testing! I tried to test it too, but seems I can't trigger a
defragment. Any hints?

Thanks!

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

^ permalink raw reply

* Re: regression with poll(2)
From: Mel Gorman @ 2012-08-20  9:04 UTC (permalink / raw)
  To: Sage Weil
  Cc: davem, netdev, linux-kernel, ceph-devel, neilb, a.p.zijlstra,
	michaelc, emunson, eric.dumazet, sebastian, cl, akpm, torvalds
In-Reply-To: <alpine.DEB.2.00.1208191051150.15570@cobra.newdream.net>

On Sun, Aug 19, 2012 at 11:49:31AM -0700, Sage Weil wrote:
> I've bisected and identified this commit:
> 
>     netvm: propagate page->pfmemalloc to skb
>     
>     The skb->pfmemalloc flag gets set to true iff during the slab allocation
>     of data in __alloc_skb that the the PFMEMALLOC reserves were used.  If the
>     packet is fragmented, it is possible that pages will be allocated from the
>     PFMEMALLOC reserve without propagating this information to the skb.  This
>     patch propagates page->pfmemalloc from pages allocated for fragments to
>     the skb.
>     
>     Signed-off-by: Mel Gorman <mgorman@suse.de>
>     Acked-by: David S. Miller <davem@davemloft.net>
>     Cc: Neil Brown <neilb@suse.de>
>     Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
>     Cc: Mike Christie <michaelc@cs.wisc.edu>
>     Cc: Eric B Munson <emunson@mgebm.net>
>     Cc: Eric Dumazet <eric.dumazet@gmail.com>
>     Cc: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
>     Cc: Mel Gorman <mgorman@suse.de>
>     Cc: Christoph Lameter <cl@linux.com>
>     Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
>     Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
> 

Ok, thanks.

> I've retested several times and confirmed that this change leads to the 
> breakage, and also confirmed that reverting it on top of -rc1 also fixes 
> the problem.
> 
> I've also added some additional instrumentation to my code and confirmed 
> that the process is blocking on poll(2) while netstat is reporting 
> data available on the socket.
> 
> What can I do to help track this down?
> 

Can the following patch be tested please? It is reported to fix an fio
regression that may be similar to what you are experiencing but has not
been picked up yet.

---8<---
From: Alex Shi <alex.shi@intel.com>
Subject: [PATCH] mm: correct page->pfmemalloc to fix deactivate_slab regression

commit cfd19c5a9ec (mm: only set page->pfmemalloc when
ALLOC_NO_WATERMARKS was used) try to narrow down page->pfmemalloc
setting, but it missed some places the pfmemalloc should be set.

So, in __slab_alloc, the unalignment pfmemalloc and ALLOC_NO_WATERMARKS
cause incorrect deactivate_slab() on our core2 server:

    64.73%           fio  [kernel.kallsyms]     [k] _raw_spin_lock
                     |
                     --- _raw_spin_lock
                        |
                        |---0.34%-- deactivate_slab
                        |          __slab_alloc
                        |          kmem_cache_alloc
                        |          |

That causes our fio sync write performance has 40% regression.

This patch move the checking in get_page_from_freelist, that resolved
this issue.

Signed-off-by: Alex Shi <alex.shi@intel.com>
---
 mm/page_alloc.c |   21 +++++++++++----------
 1 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 009ac28..07f1924 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1928,6 +1928,17 @@ this_zone_full:
 		zlc_active = 0;
 		goto zonelist_scan;
 	}
+
+	if (page)
+		/*
+		 * page->pfmemalloc is set when ALLOC_NO_WATERMARKS was
+		 * necessary to allocate the page. The expectation is
+		 * that the caller is taking steps that will free more
+		 * memory. The caller should avoid the page being used
+		 * for !PFMEMALLOC purposes.
+		 */
+		page->pfmemalloc = !!(alloc_flags & ALLOC_NO_WATERMARKS);
+
 	return page;
 }
 
@@ -2389,14 +2400,6 @@ rebalance:
 				zonelist, high_zoneidx, nodemask,
 				preferred_zone, migratetype);
 		if (page) {
-			/*
-			 * page->pfmemalloc is set when ALLOC_NO_WATERMARKS was
-			 * necessary to allocate the page. The expectation is
-			 * that the caller is taking steps that will free more
-			 * memory. The caller should avoid the page being used
-			 * for !PFMEMALLOC purposes.
-			 */
-			page->pfmemalloc = true;
 			goto got_pg;
 		}
 	}
@@ -2569,8 +2572,6 @@ retry_cpuset:
 		page = __alloc_pages_slowpath(gfp_mask, order,
 				zonelist, high_zoneidx, nodemask,
 				preferred_zone, migratetype);
-	else
-		page->pfmemalloc = false;
 
 	trace_mm_page_alloc(page, order, gfp_mask, migratetype);
 
-- 
1.7.5.4


^ permalink raw reply related

* Re: [PATCH 09/18] netfilter: ipv6: add IPv6 NAT support
From: Jan Engelhardt @ 2012-08-20  9:03 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netfilter-devel, netdev
In-Reply-To: <1345434006-16549-10-git-send-email-kaber@trash.net>


On Monday 2012-08-20 05:39, Patrick McHardy wrote:
>+static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = {
>+	/* Before packet filtering, change destination */
>+	{
>+		.hook		= nf_nat_ipv6_in,
>+		.owner		= THIS_MODULE,
>+		.pf		= NFPROTO_IPV6,
>+		.hooknum	= NF_INET_PRE_ROUTING,
>+		.priority	= NF_IP_PRI_NAT_DST,

NF_IP6_PRI_NAT_DST

>+		.hook		= nf_nat_ipv6_out,
>+		.owner		= THIS_MODULE,
>+		.pf		= NFPROTO_IPV6,
>+		.hooknum	= NF_INET_POST_ROUTING,
>+		.priority	= NF_IP_PRI_NAT_SRC,

IP6 too... (2 more occurrences)

>+static void nf_nat_ipv6_csum_recalc(struct sk_buff *skb,
>+				    u8 proto, void *data, __sum16 *check,
>+				    int datalen, int oldlen)
>+{
>+	const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
>+	struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
>+
>+	if (skb->ip_summed != CHECKSUM_PARTIAL) {

Maybe invert to == CHECKSUM_PARTIAL like in p06/18.


^ permalink raw reply

* Re: [PATCH 06/18] netfilter: add protocol independant NAT core
From: Jan Engelhardt @ 2012-08-20  8:57 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netfilter-devel, netdev
In-Reply-To: <1345434006-16549-7-git-send-email-kaber@trash.net>


On Monday 2012-08-20 05:39, Patrick McHardy wrote:
> 
> enum ctattr_nat {
> 	CTA_NAT_UNSPEC,
>-	CTA_NAT_MINIP,
>-	CTA_NAT_MAXIP,
>+	CTA_NAT_V4_MINIP,
>+#define CTA_NAT_MINIP CTA_NAT_V4_MINIP
>+	CTA_NAT_V4_MAXIP,
>+#define CTA_NAT_MAXIP CTA_NAT_V4_MAXIP
> 	CTA_NAT_PROTO,
> 	__CTA_NAT_MAX
> };

One could also

enum ctattr_nat {
   ...
   __CTA_NAT_MAX,

  CTA_NAT_MINIP = CTA_NAT_V4_MINIP,
  CTA_NAT_MAXIP = CTA_NAT_V4_MAXIP,
};

to provide the old names.


>diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
>index fcc543c..33372a1 100644
>--- a/net/ipv4/netfilter/Kconfig
>+++ b/net/ipv4/netfilter/Kconfig
[...]
> 
>-config NF_NAT_NEEDED
>-	bool
>-	depends on NF_NAT
>-	default y
>-

Could add "if NF_NAT_IPV4".."endif" block as appropriate around here,
to save on all the extra "depend on NF_NAT_IPV4" clauses.

> config IP_NF_TARGET_MASQUERADE
> 	tristate "MASQUERADE target support"
>-	depends on NF_NAT
>+	depends on NF_NAT_IPV4
> 	default m if NETFILTER_ADVANCED=n
> 	help
> 	  Masquerading is a special case of NAT: all outgoing connections are




>+static int nf_nat_ipv4_in_range(const struct nf_conntrack_tuple *t,
>+				const struct nf_nat_range *range)
>+{
>+	return ntohl(t->src.u3.ip) >= ntohl(range->min_addr.ip) &&
>+	       ntohl(t->src.u3.ip) <= ntohl(range->max_addr.ip);
>+}

static bool ..

>+static bool nf_nat_ipv4_manip_pkt(struct sk_buff *skb,
>+				  unsigned int iphdroff,
>+				  const struct nf_nat_l4proto *l4proto,
>+				  const struct nf_conntrack_tuple *target,
>+				  enum nf_nat_manip_type maniptype)
>+{
>+	struct iphdr *iph;
>+	unsigned int hdroff;
>+
>+	if (!skb_make_writable(skb, iphdroff + sizeof(*iph)))
>+		return false;
>+
>+	iph = (void *)skb->data + iphdroff;

Is iph = ip_hdr(skb), hdroff = iphdroff+skb_iphdrlen(iph) not usable here?

>+	hdroff = iphdroff + iph->ihl * 4;
>+
>+	if (!l4proto->manip_pkt(skb, &nf_nat_l3proto_ipv4, iphdroff, hdroff,
>+				target, maniptype))
>+		return false;
>+	iph = (void *)skb->data + iphdroff;

Is trying to avoid some GNU extensions a worthwhile goal? If so,
iph = (struct iphdr *)(skb->data + iphdroff) should be used, like in:

>+static void nf_nat_ipv4_csum_update(struct sk_buff *skb,
>+				    unsigned int iphdroff, __sum16 *check,
>+				    const struct nf_conntrack_tuple *t,
>+				    enum nf_nat_manip_type maniptype)
>+{
>+	struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
>[...]
>+}



>+static void nf_nat_ipv4_csum_recalc(struct sk_buff *skb,
>+				    u8 proto, void *data, __sum16 *check,
>+				    int datalen, int oldlen)
>+{
>+	const struct iphdr *iph = ip_hdr(skb);
>+	struct rtable *rt = skb_rtable(skb);
>+
>+	if (skb->ip_summed != CHECKSUM_PARTIAL) {
>+		if (!(rt->rt_flags & RTCF_LOCAL) &&
>+		    (!skb->dev || skb->dev->features & NETIF_F_V4_CSUM)) {
>+			skb->ip_summed = CHECKSUM_PARTIAL;
>+			skb->csum_start = skb_headroom(skb) +
>+					  skb_network_offset(skb) +
>+					  ip_hdrlen(skb);
>+			skb->csum_offset = (void *)check - data;
>+			*check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
>+						    datalen, proto, 0);
>+		} else {
>+			*check = 0;
>+			*check = csum_tcpudp_magic(iph->saddr, iph->daddr,
>+						   datalen, proto,
>+						   csum_partial(data, datalen,
>+								0));
>+			if (proto == IPPROTO_UDP && !*check)
>+				*check = CSUM_MANGLED_0;
>+		}
>+	} else
>+		inet_proto_csum_replace2(check, skb,
>+					 htons(oldlen), htons(datalen), 1);
>+}

Here is a style factory trick: invert the condition such that the
simple case is first, and the big one becomes an else if
with a reduced indent:

	if (skb->ip_summed == CHECKSUM_PARTIAL) {
		inet_proto_csum_replace2(check, skb,
					 htons(oldlen), htons(datalen), 1);
	} else if (!(rt->rt_flags & RTCF_LOCAL) &&
		    (!skb->dev || skb->dev->features & NETIF_F_V4_CSUM)) {
		skb->ip_summed = CHECKSUM_PARTIAL;
		skb->csum_start = skb_headroom(skb) +
				  skb_network_offset(skb) +
				  ip_hdrlen(skb);
		skb->csum_offset = (void *)check - data;
		*check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
					    datalen, proto, 0);
	} else {
		*check = 0;
		*check = csum_tcpudp_magic(iph->saddr, iph->daddr,
					   datalen, proto,
					   csum_partial(data, datalen,
							0));
		if (proto == IPPROTO_UDP && !*check)
			*check = CSUM_MANGLED_0;
	}


>+static void __exit nf_nat_l3proto_ipv4_exit(void)
>+{
>+	nf_nat_l3proto_unregister(&nf_nat_l3proto_ipv4);
>+	nf_nat_l4proto_unregister(NFPROTO_IPV4, &nf_nat_l4proto_icmp);
>+}
>+
>+MODULE_LICENSE("GPL");
>+MODULE_ALIAS("nf-nat-" __stringify(AF_INET));

Technically, this would have to be NFPROTO_IPV4, though GNU C has yet
to gain an extension to stringify enum constants..


>+	/* 1) If this srcip/proto/src-proto-part is currently mapped,
>+	 * and that same mapping gives a unique tuple within the given
>+	 * range, use that.
>+	 *
>+	 * This is only required for source (ie. NAT/masq) mappings.
>+	 * So far, we don't do local source mappings, so multiple
>+	 * manips not an issue.
           manips are not an issue.


>-		/* nf_conntrack_alter_reply might re-allocate extension area */
>+		/* nf_conntrack_alter_reply might re-allocate exntension aera */

extension was correct :)

>+	{
>+		.name		= "SNAT",
>+		.revision	= 1,
>+		.target		= xt_snat_target_v1,
>+		.targetsize	= sizeof(struct nf_nat_range),
>+		.table		= "nat",
>+		.hooks		= (1 << NF_INET_POST_ROUTING) |
>+				  (1 << NF_INET_LOCAL_OUT),
>+		.me		= THIS_MODULE,

 .family = NFPROTO_UNSPEC,

Just for completeness.

^ permalink raw reply

* APPROVED OF PAYMENT
From: BARCLAYS BANK UNITED KINGDOM @ 2012-08-20  8:37 UTC (permalink / raw)


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



[-- Attachment #2: BARCLAYS BANK UNITED KINGDOM RE CONFIRMATION OF PAYMENT FUND.doc --]
[-- Type: application/msword, Size: 80896 bytes --]

^ permalink raw reply

* [PATCH] iproute: Fix errno propagation from rtnl_talk
From: Pavel Emelyanov @ 2012-08-20  8:08 UTC (permalink / raw)
  To: Stephen Hemminger, Linux Netdev List

Callers of rtnl_talk check errno value for their needs. In particular, the addrs
and routes restoring code validly reports success if the EEXISTS is in there.

However, the errno value can be sometimes screwed up by the perror call. Thus
we should only set it _after_ the message was emitted.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---

diff --git a/lib/libnetlink.c b/lib/libnetlink.c
index 878911e..8e8c8b9 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -360,13 +360,14 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
 				if (l < sizeof(struct nlmsgerr)) {
 					fprintf(stderr, "ERROR truncated\n");
 				} else {
-					errno = -err->error;
-					if (errno == 0) {
+					if (!err->error) {
 						if (answer)
 							memcpy(answer, h, h->nlmsg_len);
 						return 0;
 					}
-					perror("RTNETLINK answers");
+
+					fprintf(stderr, "RTNETLINK answers: %s\n", strerror(-err->error));
+					errno = -err->error;
 				}
 				return -1;
 			}

^ permalink raw reply related

* Re: regression with poll(2)
From: Eric Dumazet @ 2012-08-20  8:07 UTC (permalink / raw)
  To: Sage Weil
  Cc: mgorman, davem, netdev, linux-kernel, ceph-devel, neilb,
	a.p.zijlstra, michaelc, emunson, sebastian, cl, akpm, torvalds
In-Reply-To: <alpine.DEB.2.00.1208191051150.15570@cobra.newdream.net>

On Sun, 2012-08-19 at 11:49 -0700, Sage Weil wrote:
> I've bisected and identified this commit:
> 
>     netvm: propagate page->pfmemalloc to skb
>     
>     The skb->pfmemalloc flag gets set to true iff during the slab allocation
>     of data in __alloc_skb that the the PFMEMALLOC reserves were used.  If the
>     packet is fragmented, it is possible that pages will be allocated from the
>     PFMEMALLOC reserve without propagating this information to the skb.  This
>     patch propagates page->pfmemalloc from pages allocated for fragments to
>     the skb.
>     
>     Signed-off-by: Mel Gorman <mgorman@suse.de>
>     Acked-by: David S. Miller <davem@davemloft.net>
>     Cc: Neil Brown <neilb@suse.de>
>     Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
>     Cc: Mike Christie <michaelc@cs.wisc.edu>
>     Cc: Eric B Munson <emunson@mgebm.net>
>     Cc: Eric Dumazet <eric.dumazet@gmail.com>
>     Cc: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
>     Cc: Mel Gorman <mgorman@suse.de>
>     Cc: Christoph Lameter <cl@linux.com>
>     Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
>     Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
> 
> I've retested several times and confirmed that this change leads to the 
> breakage, and also confirmed that reverting it on top of -rc1 also fixes 
> the problem.
> 
> I've also added some additional instrumentation to my code and confirmed 
> that the process is blocking on poll(2) while netstat is reporting 
> data available on the socket.
> 
> What can I do to help track this down?
> 
> Thanks!
> sage
> 
> 
> On Wed, 15 Aug 2012, Sage Weil wrote:
> 
> > I'm experiencing a stall with Ceph daemons communicating over TCP that 
> > occurs reliably with 3.6-rc1 (and linus/master) but not 3.5.  The basic 
> > situation is:
> > 
> >  - the socket is two processes communicating over TCP on the same host, e.g. 
> > 
> > tcp        0 2164849 10.214.132.38:6801      10.214.132.38:51729     ESTABLISHED
> > 
> >  - one end writes a bunch of data in
> >  - the other end consumes data, but at some point stalls.
> >  - reads are nonblocking, e.g.
> > 
> >   int got = ::recv( sd, buf, len, MSG_DONTWAIT );
> > 
> >  and between those calls we wait with
> > 
> >   struct pollfd pfd;
> >   short evmask;
> >   pfd.fd = sd;
> >   pfd.events = POLLIN;
> > #if defined(__linux__)
> >   pfd.events |= POLLRDHUP;
> > #endif
> > 
> >   if (poll(&pfd, 1, msgr->timeout) <= 0)
> >     return -1;
> > 
> >  - in my case the timeout is ~15 minutes.  at that point it errors out, 
> > and the daemons reconnect and continue for a while until hitting this 
> > again.
> > 
> >  - at the time of the stall, the reading process is blocked on that 
> > poll(2) call.  There are a bunch of threads stuck on poll(2), some of them 
> > stuck and some not, but they all have stacks like
> > 
> > [<ffffffff8118f6f9>] poll_schedule_timeout+0x49/0x70
> > [<ffffffff81190baf>] do_sys_poll+0x35f/0x4c0
> > [<ffffffff81190deb>] sys_poll+0x6b/0x100
> > [<ffffffff8163d369>] system_call_fastpath+0x16/0x1b
> > 
> >  - you'll note that the netstat output shows data queued:
> > 
> > tcp        0 1163264 10.214.132.36:6807      10.214.132.36:41738     ESTABLISHED
> > tcp        0 1622016 10.214.132.36:41738     10.214.132.36:6807      ESTABLISHED
> > 

In this netstat output, we can see some data in output queues, but no
data on receive queues. poll() is OK.

Some TCP frames are not properly delivered, even after a retransmit.

( to see useful stats/counters : ss -emoi dst 10.214.132.36)

For loopback transmits, skbs are taken from the output queue, cloned and
feeded to local stack.

If they have the pfmemalloc bit, they wont be delivered to normal
sockets, but dropped.

tcp_sendmsg() seems to be able to queue skbs with pfmemalloc set to
true, and this makes no sense to me.

^ permalink raw reply

* Re: [PATCH 1/2] iproute: Add magic cookie to route dump file
From: Pavel Emelyanov @ 2012-08-20  8:05 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: Stephen Hemminger, Linux Netdev List
In-Reply-To: <20120817134943.6f26a75e@nehalam.linuxnetplumber.net>

On 08/18/2012 12:49 AM, Stephen Hemminger wrote:
> On Fri, 27 Jul 2012 08:55:41 +0400
> Pavel Emelyanov <xemul@parallels.com> wrote:
> 
>> In order to somehow verify that a blob contains route dump a
>> 4-bytes magic is put at the head of the data and is checked
>> on restore.
>>
>> Magic digits are taken from Portland (OR) coordinates :) Is
>> there any more reliable way of generating such?
>>
>> Signed-of-by: Pavel Emelyanov <xemul@parallels.com>
> 
> I am planning on putting this in because there were no objections.
> Any followup updates?

Yes, I've recently found that errno propagation from rtnl_talk up to
addrs/routes restore doesn't work on some libc-s. I will post a fixing
patch soon.

Thanks,
Pavel

^ permalink raw reply

* Re: [PATCH 01/18] ipv4: fix path MTU discovery with connection tracking
From: Jan Engelhardt @ 2012-08-20  8:04 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netfilter-devel, netdev
In-Reply-To: <1345434006-16549-2-git-send-email-kaber@trash.net>

On Monday 2012-08-20 05:39, Patrick McHardy wrote:

>IPv4 conntrack defragments incoming packet at the PRE_ROUTING hook and
>(in case of forwarded packets) refragments them at POST_ROUTING
>independant of the IP_DF flag.

"independent". (also in 06/18)

^ permalink raw reply

* Re: [PATCH 05/18] netfilter: nf_nat: add protoff argument to packet mangling functions
From: Jan Engelhardt @ 2012-08-20  8:02 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netfilter-devel, netdev
In-Reply-To: <1345434006-16549-6-git-send-email-kaber@trash.net>


On Monday 2012-08-20 05:39, Patrick McHardy wrote:
>index 0bb5a69..4b59a15 100644
>--- a/include/linux/netfilter/nf_conntrack_amanda.h
>+++ b/include/linux/netfilter/nf_conntrack_amanda.h
>@@ -4,6 +4,7 @@
> 
> extern unsigned int (*nf_nat_amanda_hook)(struct sk_buff *skb,
> 					  enum ip_conntrack_info ctinfo,
>+					  unsigned int protoff,
> 					  unsigned int matchoff,
> 					  unsigned int matchlen,
> 					  struct nf_conntrack_expect *exp);

What about using a structure to collect all the accumulating parameters,
like we do for xtables match functions?

^ permalink raw reply

* Re: [PATCH 01/18] ipv4: fix path MTU discovery with connection tracking
From: Eric Dumazet @ 2012-08-20  7:41 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netfilter-devel, netdev
In-Reply-To: <1345434006-16549-2-git-send-email-kaber@trash.net>

On Mon, 2012-08-20 at 05:39 +0200, Patrick McHardy wrote:
> IPv4 conntrack defragments incoming packet at the PRE_ROUTING hook and
> (in case of forwarded packets) refragments them at POST_ROUTING
> independant of the IP_DF flag. Refragmentation uses the dst_mtu() of
> the local route without caring about the original fragment sizes,
> thereby breaking PMTUD.
> 
> This patch fixes this by keeping track of the largest received fragment
> with IP_DF set and generates an ICMP fragmentation required error during
> refragmentation if that size exceeds the MTU.
> 
> Signed-off-by: Patrick McHardy <kaber@trash.net>
> ---

Acked-by: Eric Dumazet <edumazet@google.com>



^ permalink raw reply

* [PATCH] rds: Don't disable BH on BH context
From: Ying Xue @ 2012-08-20  7:44 UTC (permalink / raw)
  To: venkat.x.venkatsubra, davem; +Cc: netdev

Since we have already in BH context when *_write_space(),
*_data_ready() as well as *_state_change() are called, it's
unnecessary to disable BH.

Signed-off-by: Ying Xue <ying.xue@windriver.com>
---
 net/rds/tcp_connect.c | 4 ++--
 net/rds/tcp_listen.c  | 4 ++--
 net/rds/tcp_recv.c    | 4 ++--
 net/rds/tcp_send.c    | 4 ++--
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/net/rds/tcp_connect.c b/net/rds/tcp_connect.c
index af95c8e..a65ee78 100644
--- a/net/rds/tcp_connect.c
+++ b/net/rds/tcp_connect.c
@@ -43,7 +43,7 @@ void rds_tcp_state_change(struct sock *sk)
 	struct rds_connection *conn;
 	struct rds_tcp_connection *tc;
 
-	read_lock_bh(&sk->sk_callback_lock);
+	read_lock(&sk->sk_callback_lock);
 	conn = sk->sk_user_data;
 	if (!conn) {
 		state_change = sk->sk_state_change;
@@ -68,7 +68,7 @@ void rds_tcp_state_change(struct sock *sk)
 			break;
 	}
 out:
-	read_unlock_bh(&sk->sk_callback_lock);
+	read_unlock(&sk->sk_callback_lock);
 	state_change(sk);
 }
 
diff --git a/net/rds/tcp_listen.c b/net/rds/tcp_listen.c
index 7298137..7787537 100644
--- a/net/rds/tcp_listen.c
+++ b/net/rds/tcp_listen.c
@@ -114,7 +114,7 @@ void rds_tcp_listen_data_ready(struct sock *sk, int bytes)
 
 	rdsdebug("listen data ready sk %p\n", sk);
 
-	read_lock_bh(&sk->sk_callback_lock);
+	read_lock(&sk->sk_callback_lock);
 	ready = sk->sk_user_data;
 	if (!ready) { /* check for teardown race */
 		ready = sk->sk_data_ready;
@@ -131,7 +131,7 @@ void rds_tcp_listen_data_ready(struct sock *sk, int bytes)
 		queue_work(rds_wq, &rds_tcp_listen_work);
 
 out:
-	read_unlock_bh(&sk->sk_callback_lock);
+	read_unlock(&sk->sk_callback_lock);
 	ready(sk, bytes);
 }
 
diff --git a/net/rds/tcp_recv.c b/net/rds/tcp_recv.c
index 6243258..4fac4f2 100644
--- a/net/rds/tcp_recv.c
+++ b/net/rds/tcp_recv.c
@@ -322,7 +322,7 @@ void rds_tcp_data_ready(struct sock *sk, int bytes)
 
 	rdsdebug("data ready sk %p bytes %d\n", sk, bytes);
 
-	read_lock_bh(&sk->sk_callback_lock);
+	read_lock(&sk->sk_callback_lock);
 	conn = sk->sk_user_data;
 	if (!conn) { /* check for teardown race */
 		ready = sk->sk_data_ready;
@@ -336,7 +336,7 @@ void rds_tcp_data_ready(struct sock *sk, int bytes)
 	if (rds_tcp_read_sock(conn, GFP_ATOMIC) == -ENOMEM)
 		queue_delayed_work(rds_wq, &conn->c_recv_w, 0);
 out:
-	read_unlock_bh(&sk->sk_callback_lock);
+	read_unlock(&sk->sk_callback_lock);
 	ready(sk, bytes);
 }
 
diff --git a/net/rds/tcp_send.c b/net/rds/tcp_send.c
index 1b4fd68..81cf5a4 100644
--- a/net/rds/tcp_send.c
+++ b/net/rds/tcp_send.c
@@ -174,7 +174,7 @@ void rds_tcp_write_space(struct sock *sk)
 	struct rds_connection *conn;
 	struct rds_tcp_connection *tc;
 
-	read_lock_bh(&sk->sk_callback_lock);
+	read_lock(&sk->sk_callback_lock);
 	conn = sk->sk_user_data;
 	if (!conn) {
 		write_space = sk->sk_write_space;
@@ -194,7 +194,7 @@ void rds_tcp_write_space(struct sock *sk)
 		queue_delayed_work(rds_wq, &conn->c_send_w, 0);
 
 out:
-	read_unlock_bh(&sk->sk_callback_lock);
+	read_unlock(&sk->sk_callback_lock);
 
 	/*
 	 * write_space is only called when data leaves tcp's send queue if
-- 
1.7.11

^ permalink raw reply related

* Re: [PATCH 4/5] drivers/net/wireless/ath/ath6kl/main.c: introduce missing initialization
From: Kalle Valo @ 2012-08-20  7:24 UTC (permalink / raw)
  To: Julia Lawall
  Cc: kernel-janitors, John W. Linville, linux-wireless, netdev,
	linux-kernel
In-Reply-To: <1345325159-7365-4-git-send-email-Julia.Lawall@lip6.fr>

On 08/19/2012 12:25 AM, Julia Lawall wrote:
> From: Julia Lawall <Julia.Lawall@lip6.fr>
> 
> The result of one call to a function is tested, and then at the second call
> to the same function, the previous result, and not the current result, is
> tested again.
> 
> The semantic match that finds this problem is as follows:
> (http://coccinelle.lip6.fr/)
> 
> // <smpl>
> @@
> expression ret;
> identifier f;
> statement S1,S2;
> @@
> 
> *ret = f(...);
> if (\(ret != 0\|ret < 0\|ret == NULL\)) S1
> ... when any
> *f(...);
> if (\(ret != 0\|ret < 0\|ret == NULL\)) S2
> // </smpl>
> 
> Signed-off-by: Julia Lawall <Julia.Lawall@lip6.fr>

Thanks, but this was already fixed in ath6kl.git by this commit:

commit 3206209f231062170f060fdbae38faacff86ddbf
Author: Pandiyarajan Pitchaimuthu <c_ppitch@qca.qualcomm.com>
Date:   Wed Jul 11 12:51:43 2012 +0530

    ath6kl: Make use of return value from ath6kl_diag_read()

    In ath6kl_read_fwlogs(), return value from ath6kl_diag_read()is not
    used to bail out in case of any errors in reading fw log. No real issue
    is observed because of this, reported by source code analyzer.

    kvalo: fix a long line warning

    Signed-off-by: Pandiyarajan Pitchaimuthu <c_ppitch@qca.qualcomm.com>
    Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>

Kalle

^ permalink raw reply

* Re: [PATCH net-next] xfrm: fix RCU bugs
From: Eric Dumazet @ 2012-08-20  7:14 UTC (permalink / raw)
  To: Fan Du; +Cc: David Miller, netdev, fengguang.wu, Priyanka Jain
In-Reply-To: <5031DA57.1000904@windriver.com>

On Mon, 2012-08-20 at 14:33 +0800, Fan Du wrote:

> And one out of topic question:
> The usage of xfrm_state_afinfo_lock/xfrm_km_lock is extremely
> similar with xfrm_policy_afinfo_lock, except the former is not so
> frequently read than that of the later.
> 
> Is it justified to convert RW xfrm_state_afinfo_lock/xfrm_km_lock into
> RCU?
> 

I would say it is justified, and easy enough.

^ permalink raw reply

* Re: [PATCH 02/11] net: add function to allocate skbuff head without data area
From: Patrick McHardy @ 2012-08-20  6:41 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: Florian.Westphal, netdev, netfilter-devel
In-Reply-To: <1345444774.5158.241.camel@edumazet-glaptop>

On Mon, 20 Aug 2012, Eric Dumazet wrote:

> On Mon, 2012-08-20 at 08:18 +0200, Patrick McHardy wrote:
>> Add a function to allocate a skbuff head without any data. This will be
>> used by memory mapped netlink to attached data from the mmaped area to
>> the skb.
>>
>> Additionally change skb_release_all() to check whether the skb has a
>> data area to allow the skb destructor to clear the data pointer in
>> case only a head has been allocated.
>
>      * ...
>
>>
>> +struct sk_buff *__alloc_skb_head(gfp_t gfp_mask, int node)
>> +{
>> +	struct sk_buff *skb;
>> +
>> +	/* Get the HEAD */
>> +	skb = kmem_cache_alloc_node(skbuff_head_cache,
>> +				    gfp_mask & ~__GFP_DMA, node);
>> +	if (!skb)
>> +		goto out;
>> +	prefetchw(skb);
>> +
>
> This prefetch is probably not worth it, since you write on skb on the
> following memset(). Cpu wont have enough 'time' to take benefit from
> this hint.

Right, I remember we talked about that before and I already removed it.
Must have forgotten to actually commit that change, thanks!

>
>> +	/*
>> +	 * Only clear those fields we need to clear, not those that we will
>> +	 * actually initialise below. Hence, don't put any more fields after
>> +	 * the tail pointer in struct sk_buff!
>> +	 */
>> +	memset(skb, 0, offsetof(struct sk_buff, tail));

^ permalink raw reply

* Re: [PATCH 02/11] net: add function to allocate skbuff head without data area
From: Eric Dumazet @ 2012-08-20  6:39 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Florian.Westphal, netdev, netfilter-devel
In-Reply-To: <1345443532-3707-3-git-send-email-kaber@trash.net>

On Mon, 2012-08-20 at 08:18 +0200, Patrick McHardy wrote:
> Add a function to allocate a skbuff head without any data. This will be
> used by memory mapped netlink to attached data from the mmaped area to
> the skb.
> 
> Additionally change skb_release_all() to check whether the skb has a
> data area to allow the skb destructor to clear the data pointer in
> case only a head has been allocated.

      * ...

>  
> +struct sk_buff *__alloc_skb_head(gfp_t gfp_mask, int node)
> +{
> +	struct sk_buff *skb;
> +
> +	/* Get the HEAD */
> +	skb = kmem_cache_alloc_node(skbuff_head_cache,
> +				    gfp_mask & ~__GFP_DMA, node);
> +	if (!skb)
> +		goto out;
> +	prefetchw(skb);
> +

This prefetch is probably not worth it, since you write on skb on the
following memset(). Cpu wont have enough 'time' to take benefit from
this hint.

> +	/*
> +	 * Only clear those fields we need to clear, not those that we will
> +	 * actually initialise below. Hence, don't put any more fields after
> +	 * the tail pointer in struct sk_buff!
> +	 */
> +	memset(skb, 0, offsetof(struct sk_buff, tail));

^ permalink raw reply

* Re: [PATCH] tc-tbf.8: Add parameter range to man page.
From: Li Wei @ 2012-08-20  6:36 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20120813083015.27b66cd7@nehalam.linuxnetplumber.net>

On 08/13/2012 11:30 PM, Stephen Hemminger wrote:
> On Tue, 7 Aug 2012 10:30:32 +0800
> Li Wei <lw@cn.fujitsu.com> wrote:
> 
>> Signed-off-by: Li Wei <lw@cn.fujitsu.com>
>> ---
>>  man/man8/tc-tbf.8 |    6 ++++++
>>  1 file changed, 6 insertions(+)
>>
>> diff --git a/man/man8/tc-tbf.8 b/man/man8/tc-tbf.8
>> index 3abb238..7b76146 100644
>> --- a/man/man8/tc-tbf.8
>> +++ b/man/man8/tc-tbf.8
>> @@ -76,6 +76,7 @@ latency parameter, which specifies the maximum amount of time a packet can
>>  sit in the TBF. The latter calculation takes into account the size of the
>>  bucket, the rate and possibly the peakrate (if set). These two parameters
>>  are mutually exclusive. 
>> +The range of parameter limit is [1, UINT32_MAX] bytes.
>>  .TP
>>  burst
>>  Also known as buffer or maxburst.
>> @@ -85,6 +86,7 @@ if you want to reach your configured rate!
>>  
>>  If your buffer is too small, packets may be dropped because more tokens arrive per timer tick than fit in your bucket.
>>  The minimum buffer size can be calculated by dividing the rate by HZ.
>> +The range of this parameter is [1, UINT32_MAX] bytes.
>>  
>>  Token usage calculations are performed using a table which by default has a resolution of 8 packets. 
>>  This resolution can be changed by specifying the 
>> @@ -96,11 +98,13 @@ this. Must be an integral power of 2.
>>  mpu
>>  A zero-sized packet does not use zero bandwidth. For ethernet, no packet uses less than 64 bytes. The Minimum Packet Unit 
>>  determines the minimal token usage (specified in bytes) for a packet. Defaults to zero.
>> +The range of this parameter is [0, UINT32_MAX] bytes.
>>  .TP
>>  rate
>>  The speed knob. See remarks above about limits! See 
>>  .BR tc (8)
>>  for units.
>> +The range of this parameter is [1, UINT32_MAX] bps.
>>  .PP
>>  Furthermore, if a peakrate is desired, the following parameters are available:
>>  
>> @@ -108,12 +112,14 @@ Furthermore, if a peakrate is desired, the following parameters are available:
>>  peakrate
>>  Maximum depletion rate of the bucket. Limited to 1mbit/s on Intel, 10mbit/s on Alpha. The peakrate does 
>>  not need to be set, it is only necessary if perfect millisecond timescale shaping is required.
>> +The range of this parameter is [1, UINT32_MAX] bps.
>>  
>>  .TP
>>  mtu/minburst
>>  Specifies the size of the peakrate bucket. For perfect accuracy, should be set to the MTU of the interface.
>>  If a peakrate is needed, but some burstiness is acceptable, this size can be raised. A 3000 byte minburst
>>  allows around 3mbit/s of peakrate, given 1000 byte packets.
>> +The range of this parameter is [1, UINT32_MAX] bytes.
>>  
>>  Like the regular burstsize you can also specify a 
>>  .B cell
> 
> Not sure about this, other qdisc don't document ranges on their man pages.
> Probably better to fix the generic documentation about qdisc parameters
> which already exists on 'tc-qdisc' man page.

Hi Stephen,

Not very clear with "the generic documentation about qdisc parameters
which already exists on 'tc-qdisc' man page", is there a separate man page
that describe qdisc parameters?

I'm reading the iproute2 and kernel code which related to TC and record the
value range for each parameter, I think that would be helpful for somebody
else.

Thanks.

> 

^ permalink raw reply

* RE: [PATCH] caif: Do not dereference NULL in chnl_recv_cb()
From: Sjur BRENDELAND @ 2012-08-20  6:33 UTC (permalink / raw)
  To: Jesper Juhl, linux-kernel@vger.kernel.org
  Cc: netdev@vger.kernel.org, David S. Miller, Daniel MARTENSSON
In-Reply-To: <alpine.LNX.2.00.1208172230570.15699@swampdragon.chaosbits.net>

> In net/caif/chnl_net.c::chnl_recv_cb() we call skb_header_pointer()
> which may return NULL, but we do not check for a NULL pointer before
> dereferencing it.
> This patch adds such a NULL check and properly free's allocated memory
> and return an error (-EINVAL) on failure - much better than crashing..
> 
> Signed-off-by: Jesper Juhl <jj@chaosbits.net>

Thank you for fixing this, the patch looks good to me.
Acked-by: Sjur Brændeland <sjur.brandeland@stericsson.com>

^ permalink raw reply

* Re: [PATCH net-next] xfrm: fix RCU bugs
From: Fan Du @ 2012-08-20  6:33 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: David Miller, netdev, fengguang.wu, Priyanka Jain
In-Reply-To: <1345440800.5158.239.camel@edumazet-glaptop>



On 2012年08月20日 13:33, Eric Dumazet wrote:
> On Mon, 2012-08-20 at 12:40 +0800, Fan Du wrote:
>> Hi Eric
>>
>> Please correct me if I'm wrong about below comments.
>>
>> On 2012年08月19日 18:31, Eric Dumazet wrote:
>>> From: Eric Dumazet<edumazet@google.com>
>>>
>>> This patch reverts commit 56892261ed1a (xfrm: Use rcu_dereference_bh to
>>> deference pointer protected by rcu_read_lock_bh), and fixes bugs
>>> introduced in commit 418a99ac6ad ( Replace rwlock on xfrm_policy_afinfo
>>> with rcu )
>>>
>>> 1) We properly use RCU variant in this file, not a mix of RCU/RCU_BH
>>>
>>> 2) We must defer some writes after the synchronize_rcu() call or a reader
>>>    can crash dereferencing NULL pointer.
>>
>> Not exactly.
>>
>> net/ipv4/xfrm4_policy.c
>> static void __exit xfrm4_policy_fini(void)
>>     ->  xfrm_policy_unregister_afinfo
>>
>> IMHO, ip stack can never be compiled as module, so is xfrm4_policy_fini
>> freed up after system bootup? which means xfrm4_policy_fini can never be
>> called.
>>
>> so an dereferencing NULL pointer by a reader could not happen.
>>
>
> Last famous words.
>
> Anyway xfrm_policy_unregister_afinfo() is also called from
> xfrm6_policy_fini(), and IPv6 is a module. The day we can rmmod it,
> we uncover this bug.
>
> RCU is complex (most people dont get it right, thats the truth),
> and we should make it rock solid, or I can guarantee you
> many patch attempts from future readers of this code.
>
> You wont tell them :
>
> "OK but dont worry we never call this function for real, why do you care
> at all"
>
You are correct!

And one out of topic question:
The usage of xfrm_state_afinfo_lock/xfrm_km_lock is extremely
similar with xfrm_policy_afinfo_lock, except the former is not so
frequently read than that of the later.

Is it justified to convert RW xfrm_state_afinfo_lock/xfrm_km_lock into
RCU?


>>>
>>> 3) Now we use the xfrm_policy_afinfo_lock spinlock only from process
>>> context, we no longer need to block BH in xfrm_policy_register_afinfo()
>>> and xfrm_policy_unregister_afinfo()
>>>
>> I don't think it's related to what kinds of locks we are using.
>> we call xfrm_policy_register_afinfo in process context, but actually
>> what xfrm_policy_afinfo_lock protected can be used in soft irq context.
>> that's why xx_bh is used in:
>
> You did an RCU conversion and obviously have little idea of what
> happened there.
>
> This _bh stuff was needed because _before_ RCU, an rwlock was used.
>
> And since read_lock() was used from BH handler, _all_ write_lock() had
> to use the write_lock_bh() variant to avoid a possible deadlock.
>
> But after RCU, this no longer is needed, as an rcu_read_lock() cannot
> block a writer anymore in the lock/unlock section.
>
> In fact, xfrm_policy_afinfo_lock could be replaced by a mutex. So _bh()
> is absolutely not needed anymore.
>
I indeed misunderstood the code a bit.
Your explanation is crystal clear, thanks :)

>
>

-- 

Love each day!
--fan

^ permalink raw reply

* [PATCH] iproute2: fix typo in help message.
From: Li Wei @ 2012-08-20  6:28 UTC (permalink / raw)
  To: shemminger; +Cc: netdev, Li Wei

Signed-off-by: Li Wei <lw@cn.fujitsu.com>
---
 bridge/fdb.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bridge/fdb.c b/bridge/fdb.c
index 2bbdaa6..c6aa08e 100644
--- a/bridge/fdb.c
+++ b/bridge/fdb.c
@@ -239,6 +239,6 @@ int do_fdb(int argc, char **argv)
 	} else
 		return fdb_show(0, NULL);
 
-	fprintf(stderr, "Command \"%s\" is unknown, try \"ip neigh help\".\n", *argv);
+	fprintf(stderr, "Command \"%s\" is unknown, try \"bridge fdb help\".\n", *argv);
 	exit(-1);
 }
-- 
1.7.10.1

^ permalink raw reply related

* [PATCH 09/11] nfnetlink: add support for memory mapped netlink
From: Patrick McHardy @ 2012-08-20  6:18 UTC (permalink / raw)
  To: Florian.Westphal; +Cc: netdev, netfilter-devel
In-Reply-To: <1345443532-3707-1-git-send-email-kaber@trash.net>

Signed-off-by: Patrick McHardy <kaber@trash.net>
---
 include/linux/netfilter/nfnetlink.h  |    2 ++
 net/netfilter/nfnetlink.c            |    7 +++++++
 net/netfilter/nfnetlink_log.c        |    9 +++++----
 net/netfilter/nfnetlink_queue_core.c |    2 +-
 4 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
index 18341cd..447d1a7 100644
--- a/include/linux/netfilter/nfnetlink.h
+++ b/include/linux/netfilter/nfnetlink.h
@@ -81,6 +81,8 @@ extern int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n);
 extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n);
 
 extern int nfnetlink_has_listeners(struct net *net, unsigned int group);
+extern struct sk_buff *nfnetlink_alloc_skb(struct net *net, unsigned int size,
+					   u32 dst_pid, gfp_t gfp_mask);
 extern int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned int group,
 			  int echo, gfp_t flags);
 extern int nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error);
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index a265033..d0aa9fc 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -111,6 +111,13 @@ int nfnetlink_has_listeners(struct net *net, unsigned int group)
 }
 EXPORT_SYMBOL_GPL(nfnetlink_has_listeners);
 
+struct sk_buff *nfnetlink_alloc_skb(struct net *net, unsigned int size,
+				    u32 dst_pid, gfp_t gfp_mask)
+{
+	return netlink_alloc_skb(net->nfnl, size, dst_pid, gfp_mask);
+}
+EXPORT_SYMBOL_GPL(nfnetlink_alloc_skb);
+
 int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid,
 		   unsigned int group, int echo, gfp_t flags)
 {
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 169ab59..6232ca8 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -296,7 +296,7 @@ nfulnl_set_flags(struct nfulnl_instance *inst, u_int16_t flags)
 }
 
 static struct sk_buff *
-nfulnl_alloc_skb(unsigned int inst_size, unsigned int pkt_size)
+nfulnl_alloc_skb(u32 peer_pid, unsigned int inst_size, unsigned int pkt_size)
 {
 	struct sk_buff *skb;
 	unsigned int n;
@@ -305,13 +305,14 @@ nfulnl_alloc_skb(unsigned int inst_size, unsigned int pkt_size)
 	 * message.  WARNING: has to be <= 128k due to slab restrictions */
 
 	n = max(inst_size, pkt_size);
-	skb = alloc_skb(n, GFP_ATOMIC);
+	skb = nfnetlink_alloc_skb(&init_net, n, peer_pid, GFP_ATOMIC);
 	if (!skb) {
 		if (n > pkt_size) {
 			/* try to allocate only as much as we need for current
 			 * packet */
 
-			skb = alloc_skb(pkt_size, GFP_ATOMIC);
+			skb = nfnetlink_alloc_skb(&init_net, pkt_size, peer_pid,
+						  GFP_ATOMIC);
 			if (!skb)
 				pr_err("nfnetlink_log: can't even alloc %u bytes\n",
 				       pkt_size);
@@ -658,7 +659,7 @@ nfulnl_log_packet(u_int8_t pf,
 	}
 
 	if (!inst->skb) {
-		inst->skb = nfulnl_alloc_skb(inst->nlbufsiz, size);
+		inst->skb = nfulnl_alloc_skb(inst->peer_pid, inst->nlbufsiz, size);
 		if (!inst->skb)
 			goto alloc_failure;
 	}
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c
index c0496a5..6983b2e 100644
--- a/net/netfilter/nfnetlink_queue_core.c
+++ b/net/netfilter/nfnetlink_queue_core.c
@@ -272,7 +272,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
 	if (queue->flags & NFQA_CFG_F_CONNTRACK)
 		ct = nfqnl_ct_get(entskb, &size, &ctinfo);
 
-	skb = alloc_skb(size, GFP_ATOMIC);
+	skb = nfnetlink_alloc_skb(&init_net, size, queue->peer_pid, GFP_ATOMIC);
 	if (!skb)
 		return NULL;
 
-- 
1.7.7.6

^ permalink raw reply related

* [PATCH 06/11] netlink: add mmap'ed netlink helper functions
From: Patrick McHardy @ 2012-08-20  6:18 UTC (permalink / raw)
  To: Florian.Westphal; +Cc: netdev, netfilter-devel
In-Reply-To: <1345443532-3707-1-git-send-email-kaber@trash.net>

Add helper functions for looking up mmap'ed frame headers, reading and writing
their status, allocating skbs with mmap'ed data areas and a poll function.

Signed-off-by: Patrick McHardy <kaber@trash.net>
---
 include/linux/netlink.h  |    8 ++
 net/netlink/af_netlink.c |  185 +++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 191 insertions(+), 2 deletions(-)

diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 3600461..98754e8 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -193,10 +193,18 @@ static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
 	return (struct nlmsghdr *)skb->data;
 }
 
+enum netlink_skb_flags {
+	NETLINK_SKB_MMAPED	= 0x1,		/* Packet data is mmapped */
+	NETLINK_SKB_TX		= 0x2,		/* Packet was sent by userspace */
+	NETLINK_SKB_DELIVERED	= 0x4,		/* Packet was delivered */
+};
+
 struct netlink_skb_parms {
 	struct ucred		creds;		/* Skb credentials	*/
 	__u32			pid;
 	__u32			dst_group;
+	__u32			flags;
+	struct sock		*sk;		/* socket owning mmaped ring */
 };
 
 #define NETLINK_CB(skb)		(*(struct netlink_skb_parms*)&((skb)->cb))
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index e20a918..3810911 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -56,6 +56,7 @@
 #include <linux/audit.h>
 #include <linux/mutex.h>
 #include <linux/vmalloc.h>
+#include <asm/cacheflush.h>
 
 #include <net/net_namespace.h>
 #include <net/sock.h>
@@ -159,6 +160,7 @@ static struct netlink_table *nl_table;
 static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait);
 
 static int netlink_dump(struct sock *sk);
+static void netlink_skb_destructor(struct sk_buff *skb);
 
 static DEFINE_RWLOCK(nl_table_lock);
 static atomic_t nl_table_users = ATOMIC_INIT(0);
@@ -176,6 +178,11 @@ static inline struct hlist_head *nl_pid_hashfn(struct nl_pid_hash *hash, u32 pid
 }
 
 #ifdef CONFIG_NETLINK_MMAP
+static bool netlink_skb_is_mmaped(const struct sk_buff *skb)
+{
+	return NETLINK_CB(skb).flags & NETLINK_SKB_MMAPED;
+}
+
 static __pure struct page *pgvec_to_page(const void *addr)
 {
 	if (is_vmalloc_addr(addr))
@@ -399,8 +406,154 @@ out:
 	mutex_unlock(&nlk->pg_vec_lock);
 	return 0;
 }
+
+static void netlink_frame_flush_dcache(const struct nl_mmap_hdr *hdr)
+{
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE == 1
+	struct page *p_start, *p_end;
+
+	/* First page is flushed through netlink_{get,set}_status */
+	p_start = pgvec_to_page(hdr + PAGE_SIZE);
+	p_end   = pgvec_to_page((void *)hdr + NL_MMAP_MSG_HDRLEN + hdr->nm_len - 1);
+	while (p_start <= p_end) {
+		flush_dcache_page(p_start);
+		p_start++;
+	}
+#endif
+}
+
+static enum nl_mmap_status netlink_get_status(const struct nl_mmap_hdr *hdr)
+{
+	smp_rmb();
+	flush_dcache_page(pgvec_to_page(hdr));
+	return hdr->nm_status;
+}
+
+static void netlink_set_status(struct nl_mmap_hdr *hdr,
+			       enum nl_mmap_status status)
+{
+	hdr->nm_status = status;
+	flush_dcache_page(pgvec_to_page(hdr));
+	smp_wmb();
+}
+
+static struct nl_mmap_hdr *
+__netlink_lookup_frame(const struct netlink_ring *ring, unsigned int pos)
+{
+	unsigned int pg_vec_pos, frame_off;
+
+	pg_vec_pos = pos / ring->frames_per_block;
+	frame_off  = pos % ring->frames_per_block;
+
+	return ring->pg_vec[pg_vec_pos] + (frame_off * ring->frame_size);
+}
+
+static struct nl_mmap_hdr *
+netlink_lookup_frame(const struct netlink_ring *ring, unsigned int pos,
+		     enum nl_mmap_status status)
+{
+	struct nl_mmap_hdr *hdr;
+
+	hdr = __netlink_lookup_frame(ring, pos);
+	if (netlink_get_status(hdr) != status)
+		return NULL;
+
+	return hdr;
+}
+
+static struct nl_mmap_hdr *
+netlink_current_frame(const struct netlink_ring *ring,
+		      enum nl_mmap_status status)
+{
+	return netlink_lookup_frame(ring, ring->head, status);
+}
+
+static struct nl_mmap_hdr *
+netlink_previous_frame(const struct netlink_ring *ring,
+		       enum nl_mmap_status status)
+{
+	unsigned int prev;
+
+	prev = ring->head ? ring->head - 1 : ring->frame_max;
+	return netlink_lookup_frame(ring, prev, status);
+}
+
+static void netlink_increment_head(struct netlink_ring *ring)
+{
+	ring->head = ring->head != ring->frame_max ? ring->head + 1 : 0;
+}
+
+static void netlink_forward_ring(struct netlink_ring *ring)
+{
+	unsigned int head = ring->head, pos = head;
+	const struct nl_mmap_hdr *hdr;
+
+	do {
+		hdr = __netlink_lookup_frame(ring, pos);
+		if (hdr->nm_status == NL_MMAP_STATUS_UNUSED)
+			break;
+		if (hdr->nm_status != NL_MMAP_STATUS_SKIP)
+			break;
+		netlink_increment_head(ring);
+	} while (ring->head != head);
+}
+
+static unsigned int netlink_poll(struct file *file, struct socket *sock,
+				 poll_table *wait)
+{
+	struct sock *sk = sock->sk;
+	struct netlink_sock *nlk = nlk_sk(sk);
+	unsigned int mask;
+
+	mask = datagram_poll(file, sock, wait);
+
+	spin_lock_bh(&sk->sk_receive_queue.lock);
+	if (nlk->rx_ring.pg_vec) {
+		netlink_forward_ring(&nlk->rx_ring);
+		if (!netlink_previous_frame(&nlk->rx_ring, NL_MMAP_STATUS_UNUSED))
+			mask |= POLLIN | POLLRDNORM;
+	}
+	spin_unlock_bh(&sk->sk_receive_queue.lock);
+
+	spin_lock_bh(&sk->sk_write_queue.lock);
+	if (nlk->tx_ring.pg_vec) {
+		if (netlink_current_frame(&nlk->tx_ring, NL_MMAP_STATUS_UNUSED))
+			mask |= POLLOUT | POLLWRNORM;
+	}
+	spin_unlock_bh(&sk->sk_write_queue.lock);
+
+	return mask;
+}
+
+static struct nl_mmap_hdr *netlink_mmap_hdr(struct sk_buff *skb)
+{
+	return (struct nl_mmap_hdr *)(skb->head - NL_MMAP_HDRLEN);
+}
+
+static void netlink_ring_setup_skb(struct sk_buff *skb, struct sock *sk,
+				   struct netlink_ring *ring,
+				   struct nl_mmap_hdr *hdr)
+{
+	unsigned int size;
+	void *data;
+
+	size = ring->frame_size - NL_MMAP_HDRLEN;
+	data = (void *)hdr + NL_MMAP_HDRLEN;
+
+	skb->head	= data;
+	skb->data	= data;
+	skb_reset_tail_pointer(skb);
+	skb->end	= skb->tail + size;
+	skb->len	= 0;
+
+	skb->destructor	= netlink_skb_destructor;
+	NETLINK_CB(skb).flags |= NETLINK_SKB_MMAPED;
+	NETLINK_CB(skb).sk = sk;
+}
 #else /* CONFIG_NETLINK_MMAP */
+#define netlink_skb_is_mmaped(skb)	false
 #define netlink_mmap			sock_no_mmap
+#define netlink_poll			datagram_poll
 #endif /* CONFIG_NETLINK_MMAP */
 
 static void netlink_destroy_callback(struct netlink_callback *cb)
@@ -417,7 +570,35 @@ static void netlink_consume_callback(struct netlink_callback *cb)
 
 static void netlink_skb_destructor(struct sk_buff *skb)
 {
-	sock_rfree(skb);
+#ifdef CONFIG_NETLINK_MMAP
+	struct nl_mmap_hdr *hdr;
+	struct netlink_ring *ring;
+	struct sock *sk;
+
+	/* If a packet from the kernel to userspace was freed because of an
+	 * error without being delivered to userspace, the kernel must reset
+	 * the status. In the direction userspace to kernel, the status is
+	 * always reset here after the packet was processed and freed.
+	 */
+	if (netlink_skb_is_mmaped(skb)) {
+		hdr = netlink_mmap_hdr(skb);
+		sk = NETLINK_CB(skb).sk;
+
+		if (!(NETLINK_CB(skb).flags & NETLINK_SKB_DELIVERED)) {
+			hdr->nm_len = 0;
+			netlink_set_status(hdr, NL_MMAP_STATUS_VALID);
+		}
+		ring = &nlk_sk(sk)->rx_ring;
+
+		WARN_ON(atomic_read(&ring->pending) == 0);
+		atomic_dec(&ring->pending);
+		sock_put(sk);
+
+		skb->data = NULL;
+	}
+#endif
+	if (skb->sk != NULL)
+		sock_rfree(skb);
 }
 
 static void netlink_skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
@@ -2400,7 +2581,7 @@ static const struct proto_ops netlink_ops = {
 	.socketpair =	sock_no_socketpair,
 	.accept =	sock_no_accept,
 	.getname =	netlink_getname,
-	.poll =		datagram_poll,
+	.poll =		netlink_poll,
 	.ioctl =	sock_no_ioctl,
 	.listen =	sock_no_listen,
 	.shutdown =	sock_no_shutdown,
-- 
1.7.7.6

^ permalink raw reply related

* [PATCH 05/11] netlink: mmaped netlink: ring setup
From: Patrick McHardy @ 2012-08-20  6:18 UTC (permalink / raw)
  To: Florian.Westphal; +Cc: netdev, netfilter-devel
In-Reply-To: <1345443532-3707-1-git-send-email-kaber@trash.net>

Add support for mmap'ed RX and TX ring setup and teardown based on the
af_packet.c code. The following patches will use this to add the real
mmap'ed receive and transmit functionality.

Signed-off-by: Patrick McHardy <kaber@trash.net>
---
 include/linux/netlink.h  |   32 +++++
 net/Kconfig              |    9 ++
 net/netlink/af_netlink.c |  288 +++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 327 insertions(+), 2 deletions(-)

diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index f74dd13..3600461 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -1,6 +1,7 @@
 #ifndef __LINUX_NETLINK_H
 #define __LINUX_NETLINK_H
 
+#include <linux/kernel.h>
 #include <linux/socket.h> /* for __kernel_sa_family_t */
 #include <linux/types.h>
 
@@ -105,11 +106,42 @@ struct nlmsgerr {
 #define NETLINK_PKTINFO		3
 #define NETLINK_BROADCAST_ERROR	4
 #define NETLINK_NO_ENOBUFS	5
+#define NETLINK_RX_RING		6
+#define NETLINK_TX_RING		7
 
 struct nl_pktinfo {
 	__u32	group;
 };
 
+struct nl_mmap_req {
+	unsigned int	nm_block_size;
+	unsigned int	nm_block_nr;
+	unsigned int	nm_frame_size;
+	unsigned int	nm_frame_nr;
+};
+
+struct nl_mmap_hdr {
+	unsigned int	nm_status;
+	unsigned int	nm_len;
+	__u32		nm_group;
+	/* credentials */
+	__u32		nm_pid;
+	__u32		nm_uid;
+	__u32		nm_gid;
+};
+
+enum nl_mmap_status {
+	NL_MMAP_STATUS_UNUSED,
+	NL_MMAP_STATUS_RESERVED,
+	NL_MMAP_STATUS_VALID,
+	NL_MMAP_STATUS_COPY,
+	NL_MMAP_STATUS_SKIP,
+};
+
+#define NL_MMAP_MSG_ALIGNMENT		NLMSG_ALIGNTO
+#define NL_MMAP_MSG_ALIGN(sz)		__ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT)
+#define NL_MMAP_HDRLEN			NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr))
+
 #define NET_MAJOR 36		/* Major 36 is reserved for networking 						*/
 
 enum {
diff --git a/net/Kconfig b/net/Kconfig
index 245831b..7f48691 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -23,6 +23,15 @@ menuconfig NET
 
 if NET
 
+config NETLINK_MMAP
+	bool "Netlink: mmaped IO"
+	help
+	  This option enables support for memory mapped netlink IO. This
+	  reduces overhead by avoiding copying data between kernel- and
+	  userspace.
+
+	  If unsure, say N.
+
 config WANT_COMPAT_NETLINK_MESSAGES
 	bool
 	help
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index e2d0177..e20a918 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -55,6 +55,7 @@
 #include <linux/types.h>
 #include <linux/audit.h>
 #include <linux/mutex.h>
+#include <linux/vmalloc.h>
 
 #include <net/net_namespace.h>
 #include <net/sock.h>
@@ -64,6 +65,20 @@
 #define NLGRPSZ(x)	(ALIGN(x, sizeof(unsigned long) * 8) / 8)
 #define NLGRPLONGS(x)	(NLGRPSZ(x)/sizeof(unsigned long))
 
+struct netlink_ring {
+	void			**pg_vec;
+	unsigned int		head;
+	unsigned int		frames_per_block;
+	unsigned int		frame_size;
+	unsigned int		frame_max;
+
+	unsigned int		pg_vec_order;
+	unsigned int		pg_vec_pages;
+	unsigned int		pg_vec_len;
+
+	atomic_t		pending;
+};
+
 struct netlink_sock {
 	/* struct sock has to be the first member of netlink_sock */
 	struct sock		sk;
@@ -82,6 +97,12 @@ struct netlink_sock {
 	void			(*netlink_rcv)(struct sk_buff *skb);
 	void			(*netlink_bind)(int group);
 	struct module		*module;
+#ifdef CONFIG_NETLINK_MMAP
+	struct mutex		pg_vec_lock;
+	struct netlink_ring	rx_ring;
+	struct netlink_ring	tx_ring;
+	atomic_t		mapped;
+#endif /* CONFIG_NETLINK_MMAP */
 };
 
 struct listeners {
@@ -154,6 +175,234 @@ static inline struct hlist_head *nl_pid_hashfn(struct nl_pid_hash *hash, u32 pid
 	return &hash->table[jhash_1word(pid, hash->rnd) & hash->mask];
 }
 
+#ifdef CONFIG_NETLINK_MMAP
+static __pure struct page *pgvec_to_page(const void *addr)
+{
+	if (is_vmalloc_addr(addr))
+		return vmalloc_to_page(addr);
+	else
+		return virt_to_page(addr);
+}
+
+static void free_pg_vec(void **pg_vec, unsigned int order, unsigned int len)
+{
+	unsigned int i;
+
+	for (i = 0; i < len; i++) {
+		if (pg_vec[i] != NULL) {
+			if (is_vmalloc_addr(pg_vec[i]))
+				vfree(pg_vec[i]);
+			else
+				free_pages((unsigned long)pg_vec[i], order);
+		}
+	}
+	kfree(pg_vec);
+}
+
+static void *alloc_one_pg_vec_page(unsigned long order)
+{
+	void *buffer;
+	gfp_t gfp_flags = GFP_KERNEL | __GFP_COMP | __GFP_ZERO |
+			  __GFP_NOWARN | __GFP_NORETRY;
+
+	buffer = (void *)__get_free_pages(gfp_flags, order);
+	if (buffer != NULL)
+		return buffer;
+
+	buffer = vzalloc((1 << order) * PAGE_SIZE);
+	if (buffer != NULL)
+		return buffer;
+
+	gfp_flags &= ~__GFP_NORETRY;
+	return (void *)__get_free_pages(gfp_flags, order);
+}
+
+static void **alloc_pg_vec(struct netlink_sock *nlk,
+			   struct nl_mmap_req *req, unsigned int order)
+{
+	unsigned int block_nr = req->nm_block_nr;
+	unsigned int i;
+	void **pg_vec, *ptr;
+
+	pg_vec = kcalloc(block_nr, sizeof(void *), GFP_KERNEL);
+	if (pg_vec == NULL)
+		return NULL;
+
+	for (i = 0; i < block_nr; i++) {
+		pg_vec[i] = ptr = alloc_one_pg_vec_page(order);
+		if (pg_vec[i] == NULL)
+			goto err1;
+	}
+
+	return pg_vec;
+err1:
+	free_pg_vec(pg_vec, order, block_nr);
+	return NULL;
+}
+
+static int netlink_set_ring(struct sock *sk, struct nl_mmap_req *req,
+			    bool closing, bool tx_ring)
+{
+	struct netlink_sock *nlk = nlk_sk(sk);
+	struct netlink_ring *ring;
+	struct sk_buff_head *queue;
+	void **pg_vec = NULL;
+	unsigned int order = 0;
+	int err;
+
+	ring  = tx_ring ? &nlk->tx_ring : &nlk->rx_ring;
+	queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue;
+
+	if (!closing) {
+		if (atomic_read(&nlk->mapped))
+			return -EBUSY;
+		if (atomic_read(&ring->pending))
+			return -EBUSY;
+	}
+
+	if (req->nm_block_nr) {
+		if (ring->pg_vec != NULL)
+			return -EBUSY;
+
+		if ((int)req->nm_block_size <= 0)
+			return -EINVAL;
+		if (!IS_ALIGNED(req->nm_block_size, PAGE_SIZE))
+			return -EINVAL;
+		if (req->nm_frame_size < NL_MMAP_HDRLEN)
+			return -EINVAL;
+		if (!IS_ALIGNED(req->nm_frame_size, NL_MMAP_MSG_ALIGNMENT))
+			return -EINVAL;
+
+		ring->frames_per_block = req->nm_block_size /
+					 req->nm_frame_size;
+		if (ring->frames_per_block == 0)
+			return -EINVAL;
+		if (ring->frames_per_block * req->nm_block_nr !=
+		    req->nm_frame_nr)
+			return -EINVAL;
+
+		order = get_order(req->nm_block_size);
+		pg_vec = alloc_pg_vec(nlk, req, order);
+		if (pg_vec == NULL)
+			return -ENOMEM;
+	} else {
+		if (req->nm_frame_nr)
+			return -EINVAL;
+	}
+
+	err = -EBUSY;
+	mutex_lock(&nlk->pg_vec_lock);
+	if (closing || atomic_read(&nlk->mapped) == 0) {
+		err = 0;
+		spin_lock_bh(&queue->lock);
+
+		ring->frame_max		= req->nm_frame_nr - 1;
+		ring->head		= 0;
+		ring->frame_size	= req->nm_frame_size;
+		ring->pg_vec_pages	= req->nm_block_size / PAGE_SIZE;
+
+		swap(ring->pg_vec_len, req->nm_block_nr);
+		swap(ring->pg_vec_order, order);
+		swap(ring->pg_vec, pg_vec);
+
+		__skb_queue_purge(queue);
+		spin_unlock_bh(&queue->lock);
+
+		WARN_ON(atomic_read(&nlk->mapped));
+	}
+	mutex_unlock(&nlk->pg_vec_lock);
+
+	if (pg_vec)
+		free_pg_vec(pg_vec, order, req->nm_block_nr);
+	return err;
+}
+
+static void netlink_mm_open(struct vm_area_struct *vma)
+{
+	struct file *file = vma->vm_file;
+	struct socket *sock = file->private_data;
+	struct sock *sk = sock->sk;
+
+	if (sk)
+		atomic_inc(&nlk_sk(sk)->mapped);
+}
+
+static void netlink_mm_close(struct vm_area_struct *vma)
+{
+	struct file *file = vma->vm_file;
+	struct socket *sock = file->private_data;
+	struct sock *sk = sock->sk;
+
+	if (sk)
+		atomic_dec(&nlk_sk(sk)->mapped);
+}
+
+static const struct vm_operations_struct netlink_mmap_ops = {
+	.open	= netlink_mm_open,
+	.close	= netlink_mm_close,
+};
+
+static int netlink_mmap(struct file *file, struct socket *sock,
+			struct vm_area_struct *vma)
+{
+	struct sock *sk = sock->sk;
+	struct netlink_sock *nlk = nlk_sk(sk);
+	struct netlink_ring *ring;
+	unsigned long start, size, expected;
+	unsigned int i;
+	int err = -EINVAL;
+
+	if (vma->vm_pgoff)
+		return -EINVAL;
+
+	mutex_lock(&nlk->pg_vec_lock);
+
+	expected = 0;
+	for (ring = &nlk->rx_ring; ring <= &nlk->tx_ring; ring++) {
+		if (ring->pg_vec == NULL)
+			continue;
+		expected += ring->pg_vec_len * ring->pg_vec_pages * PAGE_SIZE;
+	}
+
+	if (expected == 0)
+		goto out;
+
+	size = vma->vm_end - vma->vm_start;
+	if (size != expected)
+		goto out;
+
+	start = vma->vm_start;
+	for (ring = &nlk->rx_ring; ring <= &nlk->tx_ring; ring++) {
+		if (ring->pg_vec == NULL)
+			continue;
+
+		for (i = 0; i < ring->pg_vec_len; i++) {
+			struct page *page;
+			void *kaddr = ring->pg_vec[i];
+			unsigned int pg_num;
+
+			for (pg_num = 0; pg_num < ring->pg_vec_pages; pg_num++) {
+				page = pgvec_to_page(kaddr);
+				err = vm_insert_page(vma, start, page);
+				if (err < 0)
+					goto out;
+				start += PAGE_SIZE;
+				kaddr += PAGE_SIZE;
+			}
+		}
+	}
+
+	atomic_inc(&nlk->mapped);
+	vma->vm_ops = &netlink_mmap_ops;
+	err = 0;
+out:
+	mutex_unlock(&nlk->pg_vec_lock);
+	return 0;
+}
+#else /* CONFIG_NETLINK_MMAP */
+#define netlink_mmap			sock_no_mmap
+#endif /* CONFIG_NETLINK_MMAP */
+
 static void netlink_destroy_callback(struct netlink_callback *cb)
 {
 	kfree_skb(cb->skb);
@@ -191,6 +440,18 @@ static void netlink_sock_destruct(struct sock *sk)
 	}
 
 	skb_queue_purge(&sk->sk_receive_queue);
+#ifdef CONFIG_NETLINK_MMAP
+	if (1) {
+		struct nl_mmap_req req;
+
+		memset(&req, 0, sizeof(req));
+		if (nlk->rx_ring.pg_vec)
+			netlink_set_ring(sk, &req, true, false);
+		memset(&req, 0, sizeof(req));
+		if (nlk->tx_ring.pg_vec)
+			netlink_set_ring(sk, &req, true, true);
+	}
+#endif /* CONFIG_NETLINK_MMAP */
 
 	if (!sock_flag(sk, SOCK_DEAD)) {
 		printk(KERN_ERR "Freeing alive netlink socket %p\n", sk);
@@ -452,6 +713,9 @@ static int __netlink_create(struct net *net, struct socket *sock,
 		mutex_init(nlk->cb_mutex);
 	}
 	init_waitqueue_head(&nlk->wait);
+#ifdef CONFIG_NETLINK_MMAP
+	mutex_init(&nlk->pg_vec_lock);
+#endif
 
 	sk->sk_destruct = netlink_sock_destruct;
 	sk->sk_protocol = protocol;
@@ -1246,7 +1510,8 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
 	if (level != SOL_NETLINK)
 		return -ENOPROTOOPT;
 
-	if (optlen >= sizeof(int) &&
+	if (optname != NETLINK_RX_RING && optname != NETLINK_TX_RING &&
+	    optlen >= sizeof(int) &&
 	    get_user(val, (unsigned int __user *)optval))
 		return -EFAULT;
 
@@ -1295,6 +1560,25 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
 		}
 		err = 0;
 		break;
+#ifdef CONFIG_NETLINK_MMAP
+	case NETLINK_RX_RING:
+	case NETLINK_TX_RING: {
+		struct nl_mmap_req req;
+
+		/* Rings might consume more memory than queue limits, require
+		 * CAP_NET_ADMIN.
+		 */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (optlen < sizeof(req))
+			return -EINVAL;
+		if (copy_from_user(&req, optval, sizeof(req)))
+			return -EFAULT;
+		err = netlink_set_ring(sk, &req, false,
+				       optname == NETLINK_TX_RING);
+		break;
+	}
+#endif /* CONFIG_NETLINK_MMAP */
 	default:
 		err = -ENOPROTOOPT;
 	}
@@ -2124,7 +2408,7 @@ static const struct proto_ops netlink_ops = {
 	.getsockopt =	netlink_getsockopt,
 	.sendmsg =	netlink_sendmsg,
 	.recvmsg =	netlink_recvmsg,
-	.mmap =		sock_no_mmap,
+	.mmap =		netlink_mmap,
 	.sendpage =	sock_no_sendpage,
 };
 
-- 
1.7.7.6

^ permalink raw reply related

* [PATCH 11/11] netlink: add documentation for memory mapped I/O
From: Patrick McHardy @ 2012-08-20  6:18 UTC (permalink / raw)
  To: Florian.Westphal; +Cc: netdev, netfilter-devel
In-Reply-To: <1345443532-3707-1-git-send-email-kaber@trash.net>

Signed-off-by: Patrick McHardy <kaber@trash.net>
---
 Documentation/networking/netlink_mmap.txt |  337 +++++++++++++++++++++++++++++
 1 files changed, 337 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/networking/netlink_mmap.txt

diff --git a/Documentation/networking/netlink_mmap.txt b/Documentation/networking/netlink_mmap.txt
new file mode 100644
index 0000000..413c521
--- /dev/null
+++ b/Documentation/networking/netlink_mmap.txt
@@ -0,0 +1,337 @@
+This file documents how to use memory mapped I/O with netlink.
+
+Overview
+--------
+
+Memory mapped netlink I/O can be used to increase throughput and decrease
+overhead of unicast receive and transmit operations. Some netlink subsystems
+require high throughput, these are mainly the netfilter subsystems
+nfnetlink_queue and nfnetlink_log, but it can also help speed up large
+dump operations of f.i. the routing database.
+
+Memory mapped netlink I/O used two circular ring buffers for RX and TX which
+are mapped into the processes address space.
+
+The RX ring is used by the kernel to directly construct netlink messages into
+user-space memory without copying them as done with regular socket I/O,
+additionally as long as the ring contains messages no recvmsg() or poll()
+syscalls have to be issued by user-space to get more message.
+
+The TX ring is used to process messages directly from user-space memory, the
+kernel processes all messages contained in the ring using a single sendmsg()
+call.
+
+Usage overview
+--------------
+
+In order to use memory mapped netlink I/O, user-space needs three main changes:
+
+- ring setup
+- conversion of the RX path to get messages from the ring instead of recvmsg()
+- conversion of the TX path to construct messages into the ring
+
+Ring setup is done using setsockopt() to provide the ring parameters to the
+kernel, then a call to mmap() to map the ring into the processes address space:
+
+- setsockopt(fd, SOL_NETLINK, NETLINK_RX_RING, &params, sizeof(params));
+- setsockopt(fd, SOL_NETLINK, NETLINK_TX_RING, &params, sizeof(params));
+- ring = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)
+
+Usage of either ring is optional, but even if only the RX ring is used the
+mapping still needs to be writable in order to update the frame status after
+processing.
+
+Conversion of the reception path involves calling poll() on the file
+descriptor, once the socket is readable the frames from the ring are
+processsed in order until no more messages are available, as indicated by
+a status word in the frame header.
+
+On kernel side, in order to make use of memory mapped I/O on receive, the
+originating netlink subsystem needs to support memory mapped I/O, otherwise
+it will use an allocated socket buffer as usual and the contents will be
+ copied to the ring on transmission, nullifying most of the performance gains.
+Dumps of kernel databases automatically support memory mapped I/O.
+
+Conversion of the transmit path involves changing message contruction to
+use memory from the TX ring instead of (usually) a buffer declared on the
+stack and setting up the frame header approriately. Optionally poll() can
+be used to wait for free frames in the TX ring.
+
+Structured and definitions for using memory mapped I/O are contained in
+<linux/netlink.h>.
+
+RX and TX rings
+----------------
+
+Each ring contains a number of continous memory blocks, containing frames of
+fixed size dependant on the parameters used for ring setup.
+
+Ring:	[ block 0 ]
+		[ frame 0 ]
+		[ frame 1 ]
+	[ block 1 ]
+		[ frame 2 ]
+		[ frame 3 ]
+	...
+	[ block n ]
+		[ frame 2 * n ]
+		[ frame 2 * n + 1 ]
+
+The blocks are only visible to the kernel, from the point of view of user-space
+the ring just contains the frames in a continous memory zone.
+
+The ring parameters used for setting up the ring are defined as follows:
+
+struct nl_mmap_req {
+	unsigned int	nm_block_size;
+	unsigned int	nm_block_nr;
+	unsigned int	nm_frame_size;
+	unsigned int	nm_frame_nr;
+};
+
+Frames are grouped into blocks, where each block is a continous region of memory
+and holds nm_block_size / nm_frame_size frames. The total number of frames in
+the ring is nm_frame_nr. The following invariants hold:
+
+- frames_per_block = nm_block_size / nm_frame_size
+
+- nm_frame_nr = frames_per_block * nm_block_nr
+
+Some parameters are constrained, specifically:
+
+- nm_block_size must be a multiple of the architectures memory page size.
+  The getpagesize() function can be used to get the page size.
+
+- nm_frame_size must be equal or larger to NL_MMAP_HDRLEN, IOW a frame must be
+  able to hold at least the frame header
+
+- nm_frame_size must be smaller or equal to nm_block_size
+
+- nm_frame_size must be a multiple of NL_MMAP_MSG_ALIGNMENT
+
+- nm_frame_nr must equal the actual number of frames as specified above.
+
+When the kernel can't allocate phsyically continous memory for a ring block,
+it will fall back to use physically discontinous memory. This might affect
+performance negatively, in order to avoid this the nm_frame_size parameter
+should be chosen to be as small as possible for the required frame size and
+the number of blocks should be increased instead.
+
+Ring frames
+------------
+
+Each frames contain a frame header, consisting of a synchronization word and some
+meta-data, and the message itself.
+
+Frame:	[ header message ]
+
+The frame header is defined as follows:
+
+struct nl_mmap_hdr {
+	unsigned int	nm_status;
+	unsigned int	nm_len;
+	__u32		nm_group;
+	/* credentials */
+	__u32		nm_pid;
+	__u32		nm_uid;
+	__u32		nm_gid;
+};
+
+- nm_status is used for synchronizing processing between the kernel and user-
+  space and specifies ownership of the frame as well as the operation to perform
+
+- nm_len contains the length of the message contained in the data area
+
+- nm_group specified the destination multicast group of message
+
+- nm_pid, nm_uid and nm_gid contain the netlink pid, UID and GID of the sending
+  process. These values correspond to the data available using SOCK_PASSCRED in
+  the SCM_CREDENTIALS cmsg.
+
+The possible values in the status word are:
+
+- NL_MMAP_STATUS_UNUSED:
+	RX ring:	frame belongs to the kernel and contains no message
+			for user-space. Approriate action is to invoke poll()
+			to wait for new messages.
+
+	TX ring:	frame belongs to user-space and can be used for
+			message construction.
+
+- NL_MMAP_STATUS_RESERVED:
+	RX ring only:	frame is currently used by the kernel for message
+			construction and contains no valid message yet.
+			Appropriate action is to invoke poll() to wait for
+			new messages.
+
+- NL_MMAP_STATUS_VALID:
+	RX ring:	frame contains a valid message. Approriate action is
+			to process the message and release the frame back to
+			the kernel by setting the status to
+			NL_MMAP_STATUS_UNUSED or queue the frame by setting the
+			status to NL_MMAP_STATUS_SKIP.
+
+	TX ring:	the frame contains a valid message from user-space to
+			be processed by the kernel. After completing processing
+			the kernel will release the frame back to user-space by
+			setting the status to NL_MMAP_STATUS_UNUSED.
+
+- NL_MMAP_STATUS_COPY:
+	RX ring only:	a message is ready to be processed but could not be
+			stored in the ring, either because it exceeded the
+			frame size or because the originating subsystem does
+			not support memory mapped I/O. Appropriate action is
+			to invoke recvmsg() to receive the message and release
+			the frame back to the kernel by setting the status to
+			NL_MMAP_STATUS_UNUSED.
+
+- NL_MMAP_STATUS_SKIP:
+	RX ring only:	user-space queued the message for later processing, but
+			processed some messages following it in the ring. The
+			kernel should skip this frame when looking for unused
+			frames.
+
+The data area of a frame begins at a offset of NL_MMAP_HDRLEN relative to the
+frame header.
+
+TX limitations
+--------------
+
+Kernel processing usually involves validation of the message received by
+user-space, then processing its contents. The kernel must assure that
+userspace is not able to modify the message contents after they have been
+validated. In order to do so, the message is copied from the ring frame
+to an allocated buffer if either of these conditions is false:
+
+- only a single mapping of the ring exists
+- the file descriptor is not shared between processes
+
+This means that for threaded programs, the kernel will fall back to copying.
+
+Example
+-------
+
+Ring setup:
+
+	unsigned int block_size = 16 * getpagesize();
+	struct nl_mmap_req req = {
+		.nm_block_size		= block_size,
+		.nm_block_nr		= 64,
+		.nm_frame_size		= 16384,
+		.nm_frame_nr		= 64 * block_size / 16384,
+	};
+	unsigned int ring_size;
+	void *rx_ring, *tx_ring;
+
+	/* Configure ring parameters */
+	if (setsockopt(fd, NETLINK_RX_RING, &req, sizeof(req)) < 0)
+		exit(1);
+	if (setsockopt(fd, NETLINK_TX_RING, &req, sizeof(req)) < 0)
+		exit(1)
+
+	/* Calculate size of each invididual ring */
+	ring_size = req.nm_block_nr * req.nm_block_size;
+
+	/* Map RX/TX rings. The TX ring is located after the RX ring */
+	rx_ring = mmap(NULL, 2 * ring_size, PROT_READ | PROT_WRITE,
+		       MAP_SHARED, fd, 0);
+	if ((long)rx_ring == -1L)
+		exit(1);
+	tx_ring = rx_ring + ring_size:
+
+Message reception:
+
+This example assumes some ring parameters of the ring setup are available.
+
+	unsigned int frame_offset = 0;
+	struct nl_mmap_hdr *hdr;
+	struct nlmsghdr *nlh;
+	unsigned char buf[16384];
+	ssize_t len;
+
+	while (1) {
+		struct pollfd pfds[1];
+
+		pfds[0].fd	= fd;
+		pfds[0].events	= POLLIN | POLLERR;
+		pfds[0].revents	= 0;
+
+		if (poll(pfds, 1, -1) < 0 && errno != -EINTR)
+			exit(1);
+
+		/* Check for errors. Error handling omitted */
+		if (pfds[0].revents & POLLERR)
+			<handle error>
+
+		/* If no new messages, poll again */
+		if (!(pfds[0].revents & POLLIN))
+			continue;
+
+		/* Process all frames */
+		while (1) {
+			/* Get next frame header */
+			hdr = rx_ring + frame_offset;
+
+			if (hdr->nm_status == NL_MMAP_STATUS_VALID)
+				/* Regular memory mapped frame */
+				nlh = (void *hdr) + NL_MMAP_HDRLEN;
+				len = hdr->nm_len;
+
+				/* Release empty message immediately. May happen
+				 * on error during message construction.
+				 */
+				if (len == 0)
+					goto release;
+			} else if (hdr->nm_status == NL_MMAP_STATUS_COPY) {
+				/* Frame queued to socket receive queue */
+				len = recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
+				if (len <= 0)
+					break;
+				nlh = buf;
+			} else
+				/* No more messages to process, continue polling */
+				break;
+
+			process_msg(nlh);
+release:
+			/* Release frame back to the kernel */
+			hdr->nm_status = NL_MMAP_STATUS_UNUSED;
+
+			/* Advance frame offset to next frame */
+			frame_offset = (frame_offset + frame_size) % ring_size;
+		}
+	}
+
+Message transmission:
+
+This example assumes some ring parameters of the ring setup are available.
+A single message is constructed and transmitted, to send multiple messages
+at once they would be constructed in consecutive frames before a final call
+to sendto().
+
+	unsigned int frame_offset = 0;
+	struct nl_mmap_hdr *hdr;
+	struct nlmsghdr *nlh;
+	struct sockaddr_nl addr = {
+		.nl_family	= AF_NETLINK,
+	};
+
+	hdr = tx_ring + frame_offset;
+	if (hdr->nm_status != NL_MMAP_STATUS_UNUSED)
+		/* No frame available. Use poll() to avoid. */
+		exit(1);
+
+	nlh = (void *)hdr + NL_MMAP_HDRLEN;
+
+	/* Build message */
+	build_message(nlh);
+
+	/* Fill frame header: length and status need to be set */
+	hdr->nm_len	= nlh->nlmsg_len;
+	hdr->nm_status	= NL_MMAP_STATUS_VALID;
+
+	if (sendto(fd, NULL, 0, 0, &addr, sizeof(addr)) < 0)
+		exit(1);
+
+	/* Advance frame offset to next frame */
+	frame_offset = (frame_offset + frame_size) % ring_size;
-- 
1.7.7.6


^ permalink raw reply related


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