diff mbox

[nf-next,5/9] netfilter: conntrack: small refactoring of conntrack seq_printf

Message ID 1461863628-23350-6-git-send-email-fw@strlen.de
State Accepted
Delegated to: Pablo Neira
Headers show

Commit Message

Florian Westphal April 28, 2016, 5:13 p.m. UTC
The iteration process is lockless, so we test if the conntrack object is
eligible for printing (e.g. is AF_INET) after obtaining the reference
count.

Once we put all conntracks into same hash table we might see more
entries that need to be skipped.

So add a helper and first perform the test in a lockless fashion
for fast skip.

Once we obtain the reference count, just repeat the check.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 .../netfilter/nf_conntrack_l3proto_ipv4_compat.c   | 24 +++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)

Comments

Pablo Neira Ayuso May 3, 2016, 6:12 p.m. UTC | #1
On Thu, Apr 28, 2016 at 07:13:44PM +0200, Florian Westphal wrote:
> The iteration process is lockless, so we test if the conntrack object is
> eligible for printing (e.g. is AF_INET) after obtaining the reference
> count.
> 
> Once we put all conntracks into same hash table we might see more
> entries that need to be skipped.
> 
> So add a helper and first perform the test in a lockless fashion
> for fast skip.
> 
> Once we obtain the reference count, just repeat the check.
> 
> Signed-off-by: Florian Westphal <fw@strlen.de>
> ---
>  .../netfilter/nf_conntrack_l3proto_ipv4_compat.c   | 24 +++++++++++++++++-----
>  1 file changed, 19 insertions(+), 5 deletions(-)
> 
> diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
> index f0dfe92..483cf79 100644
> --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
> +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
> @@ -114,6 +114,19 @@ static inline void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
>  }
>  #endif
>  
> +static bool ct_seq_should_skip(const struct nf_conn *ct,
> +			       const struct nf_conntrack_tuple_hash *hash)
> +{
> +	/* we only want to print DIR_ORIGINAL */
> +	if (NF_CT_DIRECTION(hash))
> +		return true;
> +
> +	if (nf_ct_l3num(ct) != AF_INET)
> +		return true;
> +
> +	return false;
> +}
> +
>  static int ct_seq_show(struct seq_file *s, void *v)
>  {
>  	struct nf_conntrack_tuple_hash *hash = v;
> @@ -123,14 +136,15 @@ static int ct_seq_show(struct seq_file *s, void *v)
>  	int ret = 0;
>  
>  	NF_CT_ASSERT(ct);
> -	if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
> +	if (ct_seq_should_skip(ct, hash))
>  		return 0;
>  
> +	if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
> +		return 0;
>  
> -	/* we only want to print DIR_ORIGINAL */
> -	if (NF_CT_DIRECTION(hash))
> -		goto release;
> -	if (nf_ct_l3num(ct) != AF_INET)
> +	/* check if we raced w. object reuse */
> +	if (!nf_ct_is_confirmed(ct) ||

This refactoring includes this new check, is this intentional?

> +	    ct_seq_should_skip(ct, hash))
>  		goto release;
>  
>  	l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct));
> -- 
> 2.7.3
> 
--
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
Florian Westphal May 3, 2016, 10:27 p.m. UTC | #2
Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > -	if (NF_CT_DIRECTION(hash))
> > -		goto release;
> > -	if (nf_ct_l3num(ct) != AF_INET)
> > +	/* check if we raced w. object reuse */
> > +	if (!nf_ct_is_confirmed(ct) ||
> 
> This refactoring includes this new check, is this intentional?

Hmm, yes and no.

I should have put it in an extra commit :-/

Without this, we might erronously print a conntrack that is NEW
and which isn't confirmed yet.

We won't crash since seq_print doesn't depend on extensions being
set up properly, but it seems better to only display those conntracks
that are part of the conntrack hash table (i.e., have the confirmed bit
set).

Let me know if you want me to respin this as a separate fix, 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
Pablo Neira Ayuso May 3, 2016, 10:28 p.m. UTC | #3
On Tue, May 03, 2016 at 08:12:50PM +0200, Pablo Neira Ayuso wrote:
> On Thu, Apr 28, 2016 at 07:13:44PM +0200, Florian Westphal wrote:
> > The iteration process is lockless, so we test if the conntrack object is
> > eligible for printing (e.g. is AF_INET) after obtaining the reference
> > count.
> > 
> > Once we put all conntracks into same hash table we might see more
> > entries that need to be skipped.
> > 
> > So add a helper and first perform the test in a lockless fashion
> > for fast skip.
> > 
> > Once we obtain the reference count, just repeat the check.
> > 
> > Signed-off-by: Florian Westphal <fw@strlen.de>
> > ---
> >  .../netfilter/nf_conntrack_l3proto_ipv4_compat.c   | 24 +++++++++++++++++-----
> >  1 file changed, 19 insertions(+), 5 deletions(-)
> > 
> > diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
> > index f0dfe92..483cf79 100644
> > --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
> > +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
> > @@ -114,6 +114,19 @@ static inline void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
> >  }
> >  #endif
> >  
> > +static bool ct_seq_should_skip(const struct nf_conn *ct,
> > +			       const struct nf_conntrack_tuple_hash *hash)
> > +{
> > +	/* we only want to print DIR_ORIGINAL */
> > +	if (NF_CT_DIRECTION(hash))
> > +		return true;
> > +
> > +	if (nf_ct_l3num(ct) != AF_INET)
> > +		return true;
> > +
> > +	return false;
> > +}
> > +
> >  static int ct_seq_show(struct seq_file *s, void *v)
> >  {
> >  	struct nf_conntrack_tuple_hash *hash = v;
> > @@ -123,14 +136,15 @@ static int ct_seq_show(struct seq_file *s, void *v)
> >  	int ret = 0;
> >  
> >  	NF_CT_ASSERT(ct);
> > -	if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
> > +	if (ct_seq_should_skip(ct, hash))
> >  		return 0;
> >  
> > +	if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
> > +		return 0;
> >  
> > -	/* we only want to print DIR_ORIGINAL */
> > -	if (NF_CT_DIRECTION(hash))
> > -		goto release;
> > -	if (nf_ct_l3num(ct) != AF_INET)
> > +	/* check if we raced w. object reuse */
> > +	if (!nf_ct_is_confirmed(ct) ||
> 
> This refactoring includes this new check, is this intentional?

It seems this check was previously missing, I can just amend the
commit log with a couple of lines to document that this patch also
includes this missing check. No problem.
--
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
Pablo Neira Ayuso May 4, 2016, 9:19 a.m. UTC | #4
On Wed, May 04, 2016 at 12:27:36AM +0200, Florian Westphal wrote:
> Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > > -	if (NF_CT_DIRECTION(hash))
> > > -		goto release;
> > > -	if (nf_ct_l3num(ct) != AF_INET)
> > > +	/* check if we raced w. object reuse */
> > > +	if (!nf_ct_is_confirmed(ct) ||
> > 
> > This refactoring includes this new check, is this intentional?
> 
> Hmm, yes and no.
> 
> I should have put it in an extra commit :-/
> 
> Without this, we might erronously print a conntrack that is NEW
> and which isn't confirmed yet.
> 
> We won't crash since seq_print doesn't depend on extensions being
> set up properly, but it seems better to only display those conntracks
> that are part of the conntrack hash table (i.e., have the confirmed bit
> set).

I see, a conntrack that shouldn't be printed be sneak in the listing.

> Let me know if you want me to respin this as a separate fix, thanks!

I will just append a notice on the commit message before applying.
--
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
diff mbox

Patch

diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
index f0dfe92..483cf79 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
@@ -114,6 +114,19 @@  static inline void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
 }
 #endif
 
+static bool ct_seq_should_skip(const struct nf_conn *ct,
+			       const struct nf_conntrack_tuple_hash *hash)
+{
+	/* we only want to print DIR_ORIGINAL */
+	if (NF_CT_DIRECTION(hash))
+		return true;
+
+	if (nf_ct_l3num(ct) != AF_INET)
+		return true;
+
+	return false;
+}
+
 static int ct_seq_show(struct seq_file *s, void *v)
 {
 	struct nf_conntrack_tuple_hash *hash = v;
@@ -123,14 +136,15 @@  static int ct_seq_show(struct seq_file *s, void *v)
 	int ret = 0;
 
 	NF_CT_ASSERT(ct);
-	if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
+	if (ct_seq_should_skip(ct, hash))
 		return 0;
 
+	if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
+		return 0;
 
-	/* we only want to print DIR_ORIGINAL */
-	if (NF_CT_DIRECTION(hash))
-		goto release;
-	if (nf_ct_l3num(ct) != AF_INET)
+	/* check if we raced w. object reuse */
+	if (!nf_ct_is_confirmed(ct) ||
+	    ct_seq_should_skip(ct, hash))
 		goto release;
 
 	l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct));