Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: conntrack: avoid useless indirection during conntrack destruction

nf_ct_put() results in a usesless indirection:

nf_ct_put -> nf_conntrack_put -> nf_conntrack_destroy -> rcu readlock +
indirect call of ct_hooks->destroy().

There are two _put helpers:
nf_ct_put and nf_conntrack_put. The latter is what should be used in
code that MUST NOT cause a linker dependency on the conntrack module
(e.g. calls from core network stack).

Everyone else should call nf_ct_put() instead.

A followup patch will convert a few nf_conntrack_put() calls to
nf_ct_put(), in particular from modules that already have a conntrack
dependency such as act_ct or even nf_conntrack itself.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Florian Westphal and committed by
Pablo Neira Ayuso
6ae7989c 285c8a7a

+14 -8
+2
include/linux/netfilter/nf_conntrack_common.h
··· 29 29 }; 30 30 31 31 void nf_conntrack_destroy(struct nf_conntrack *nfct); 32 + 33 + /* like nf_ct_put, but without module dependency on nf_conntrack */ 32 34 static inline void nf_conntrack_put(struct nf_conntrack *nfct) 33 35 { 34 36 if (nfct && refcount_dec_and_test(&nfct->use))
+6 -2
include/net/netfilter/nf_conntrack.h
··· 76 76 * Hint, SKB address this struct and refcnt via skb->_nfct and 77 77 * helpers nf_conntrack_get() and nf_conntrack_put(). 78 78 * Helper nf_ct_put() equals nf_conntrack_put() by dec refcnt, 79 + * except that the latter uses internal indirection and does not 80 + * result in a conntrack module dependency. 79 81 * beware nf_ct_get() is different and don't inc refcnt. 80 82 */ 81 83 struct nf_conntrack ct_general; ··· 172 170 return (struct nf_conn *)(nfct & NFCT_PTRMASK); 173 171 } 174 172 173 + void nf_ct_destroy(struct nf_conntrack *nfct); 174 + 175 175 /* decrement reference count on a conntrack */ 176 176 static inline void nf_ct_put(struct nf_conn *ct) 177 177 { 178 - WARN_ON(!ct); 179 - nf_conntrack_put(&ct->ct_general); 178 + if (ct && refcount_dec_and_test(&ct->ct_general.use)) 179 + nf_ct_destroy(&ct->ct_general); 180 180 } 181 181 182 182 /* Protocol module loading */
+6 -6
net/netfilter/nf_conntrack_core.c
··· 558 558 559 559 #define NFCT_ALIGN(len) (((len) + NFCT_INFOMASK) & ~NFCT_INFOMASK) 560 560 561 - /* Released via destroy_conntrack() */ 561 + /* Released via nf_ct_destroy() */ 562 562 struct nf_conn *nf_ct_tmpl_alloc(struct net *net, 563 563 const struct nf_conntrack_zone *zone, 564 564 gfp_t flags) ··· 612 612 #endif 613 613 } 614 614 615 - static void 616 - destroy_conntrack(struct nf_conntrack *nfct) 615 + void nf_ct_destroy(struct nf_conntrack *nfct) 617 616 { 618 617 struct nf_conn *ct = (struct nf_conn *)nfct; 619 618 620 - pr_debug("destroy_conntrack(%p)\n", ct); 619 + pr_debug("%s(%p)\n", __func__, ct); 621 620 WARN_ON(refcount_read(&nfct->use) != 0); 622 621 623 622 if (unlikely(nf_ct_is_template(ct))) { ··· 642 643 if (ct->master) 643 644 nf_ct_put(ct->master); 644 645 645 - pr_debug("destroy_conntrack: returning ct=%p to slab\n", ct); 646 + pr_debug("%s: returning ct=%p to slab\n", __func__, ct); 646 647 nf_conntrack_free(ct); 647 648 } 649 + EXPORT_SYMBOL(nf_ct_destroy); 648 650 649 651 static void nf_ct_delete_from_lists(struct nf_conn *ct) 650 652 { ··· 2771 2771 2772 2772 static const struct nf_ct_hook nf_conntrack_hook = { 2773 2773 .update = nf_conntrack_update, 2774 - .destroy = destroy_conntrack, 2774 + .destroy = nf_ct_destroy, 2775 2775 .get_tuple_skb = nf_conntrack_get_tuple_skb, 2776 2776 .attach = nf_conntrack_attach, 2777 2777 };