netfilter: expect: add and use nf_ct_expect_iterate helpers
authorFlorian Westphal <fw@strlen.de>
Tue, 25 Jul 2017 22:02:31 +0000 (00:02 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 31 Jul 2017 17:09:38 +0000 (19:09 +0200)
We have several spots that open-code a expect walk, add a helper
that is similar to nf_ct_iterate_destroy/nf_ct_iterate_cleanup.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/net/netfilter/nf_conntrack_expect.h
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_helper.c
net/netfilter/nf_conntrack_netlink.c

index 2ba54feaccd8d4a6ebccc84fd5e21f45bff665ca..818def0111101cf9d82f9f3ea54b1bb73545f488 100644 (file)
@@ -107,6 +107,11 @@ void nf_ct_remove_expectations(struct nf_conn *ct);
 void nf_ct_unexpect_related(struct nf_conntrack_expect *exp);
 bool nf_ct_remove_expect(struct nf_conntrack_expect *exp);
 
+void nf_ct_expect_iterate_destroy(bool (*iter)(struct nf_conntrack_expect *e, void *data), void *data);
+void nf_ct_expect_iterate_net(struct net *net,
+                             bool (*iter)(struct nf_conntrack_expect *e, void *data),
+                              void *data, u32 portid, int report);
+
 /* Allocate space for an expectation: this is mandatory before calling
    nf_ct_expect_related.  You will have to call put afterwards. */
 struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me);
index 2c63808bea96e320fc9c529493030aba45a233a6..dad2c0c22ad58bf5ddb0fa4aaf1cb888eccd7e4c 100644 (file)
@@ -474,6 +474,60 @@ out:
 }
 EXPORT_SYMBOL_GPL(nf_ct_expect_related_report);
 
+void nf_ct_expect_iterate_destroy(bool (*iter)(struct nf_conntrack_expect *e, void *data),
+                                 void *data)
+{
+       struct nf_conntrack_expect *exp;
+       const struct hlist_node *next;
+       unsigned int i;
+
+       spin_lock_bh(&nf_conntrack_expect_lock);
+
+       for (i = 0; i < nf_ct_expect_hsize; i++) {
+               hlist_for_each_entry_safe(exp, next,
+                                         &nf_ct_expect_hash[i],
+                                         hnode) {
+                       if (iter(exp, data) && del_timer(&exp->timeout)) {
+                               nf_ct_unlink_expect(exp);
+                               nf_ct_expect_put(exp);
+                       }
+               }
+       }
+
+       spin_unlock_bh(&nf_conntrack_expect_lock);
+}
+EXPORT_SYMBOL_GPL(nf_ct_expect_iterate_destroy);
+
+void nf_ct_expect_iterate_net(struct net *net,
+                             bool (*iter)(struct nf_conntrack_expect *e, void *data),
+                             void *data,
+                             u32 portid, int report)
+{
+       struct nf_conntrack_expect *exp;
+       const struct hlist_node *next;
+       unsigned int i;
+
+       spin_lock_bh(&nf_conntrack_expect_lock);
+
+       for (i = 0; i < nf_ct_expect_hsize; i++) {
+               hlist_for_each_entry_safe(exp, next,
+                                         &nf_ct_expect_hash[i],
+                                         hnode) {
+
+                       if (!net_eq(nf_ct_exp_net(exp), net))
+                               continue;
+
+                       if (iter(exp, data) && del_timer(&exp->timeout)) {
+                               nf_ct_unlink_expect_report(exp, portid, report);
+                               nf_ct_expect_put(exp);
+                       }
+               }
+       }
+
+       spin_unlock_bh(&nf_conntrack_expect_lock);
+}
+EXPORT_SYMBOL_GPL(nf_ct_expect_iterate_net);
+
 #ifdef CONFIG_NF_CONNTRACK_PROCFS
 struct ct_expect_iter_state {
        struct seq_net_private p;
index 9129bb3b51535a76f3aeef83c8f16fb13ee6f656..551a1eddf0fab75eccf803b9711e069e61e60d5d 100644 (file)
@@ -437,12 +437,22 @@ out:
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);
 
-void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
 {
-       struct nf_conntrack_expect *exp;
-       const struct hlist_node *next;
-       unsigned int i;
+       struct nf_conn_help *help = nfct_help(exp->master);
+       const struct nf_conntrack_helper *me = data;
+       const struct nf_conntrack_helper *this;
+
+       if (exp->helper == me)
+               return true;
 
+       this = rcu_dereference_protected(help->helper,
+                                        lockdep_is_held(&nf_conntrack_expect_lock));
+       return this == me;
+}
+
+void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+{
        mutex_lock(&nf_ct_helper_mutex);
        hlist_del_rcu(&me->hnode);
        nf_ct_helper_count--;
@@ -453,21 +463,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
         */
        synchronize_rcu();
 
-       /* Get rid of expectations */
-       spin_lock_bh(&nf_conntrack_expect_lock);
-       for (i = 0; i < nf_ct_expect_hsize; i++) {
-               hlist_for_each_entry_safe(exp, next,
-                                         &nf_ct_expect_hash[i], hnode) {
-                       struct nf_conn_help *help = nfct_help(exp->master);
-                       if ((rcu_dereference_protected(
-                                       help->helper,
-                                       lockdep_is_held(&nf_conntrack_expect_lock)
-                                       ) == me || exp->helper == me))
-                               nf_ct_remove_expect(exp);
-               }
-       }
-       spin_unlock_bh(&nf_conntrack_expect_lock);
-
+       nf_ct_expect_iterate_destroy(expect_iter_me, NULL);
        nf_ct_iterate_destroy(unhelp, me);
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
index 4dba71de4de7952c63481e8918af5ec00706ea9a..4922c8aefb2a1c4fd4227ac40e0004a456dfa44e 100644 (file)
@@ -2898,6 +2898,21 @@ out:
        return err == -EAGAIN ? -ENOBUFS : err;
 }
 
+static bool expect_iter_name(struct nf_conntrack_expect *exp, void *data)
+{
+       const struct nf_conn_help *m_help;
+       const char *name = data;
+
+       m_help = nfct_help(exp->master);
+
+       return strcmp(m_help->helper->name, name) == 0;
+}
+
+static bool expect_iter_all(struct nf_conntrack_expect *exp, void *data)
+{
+       return true;
+}
+
 static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
                                struct sk_buff *skb, const struct nlmsghdr *nlh,
                                const struct nlattr * const cda[],
@@ -2906,10 +2921,8 @@ static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
        struct nf_conntrack_expect *exp;
        struct nf_conntrack_tuple tuple;
        struct nfgenmsg *nfmsg = nlmsg_data(nlh);
-       struct hlist_node *next;
        u_int8_t u3 = nfmsg->nfgen_family;
        struct nf_conntrack_zone zone;
-       unsigned int i;
        int err;
 
        if (cda[CTA_EXPECT_TUPLE]) {
@@ -2949,49 +2962,15 @@ static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
                nf_ct_expect_put(exp);
        } else if (cda[CTA_EXPECT_HELP_NAME]) {
                char *name = nla_data(cda[CTA_EXPECT_HELP_NAME]);
-               struct nf_conn_help *m_help;
 
-               /* delete all expectations for this helper */
-               spin_lock_bh(&nf_conntrack_expect_lock);
-               for (i = 0; i < nf_ct_expect_hsize; i++) {
-                       hlist_for_each_entry_safe(exp, next,
-                                                 &nf_ct_expect_hash[i],
-                                                 hnode) {
-
-                               if (!net_eq(nf_ct_exp_net(exp), net))
-                                       continue;
-
-                               m_help = nfct_help(exp->master);
-                               if (!strcmp(m_help->helper->name, name) &&
-                                   del_timer(&exp->timeout)) {
-                                       nf_ct_unlink_expect_report(exp,
-                                                       NETLINK_CB(skb).portid,
-                                                       nlmsg_report(nlh));
-                                       nf_ct_expect_put(exp);
-                               }
-                       }
-               }
-               spin_unlock_bh(&nf_conntrack_expect_lock);
+               nf_ct_expect_iterate_net(net, expect_iter_name, name,
+                                        NETLINK_CB(skb).portid,
+                                        nlmsg_report(nlh));
        } else {
                /* This basically means we have to flush everything*/
-               spin_lock_bh(&nf_conntrack_expect_lock);
-               for (i = 0; i < nf_ct_expect_hsize; i++) {
-                       hlist_for_each_entry_safe(exp, next,
-                                                 &nf_ct_expect_hash[i],
-                                                 hnode) {
-
-                               if (!net_eq(nf_ct_exp_net(exp), net))
-                                       continue;
-
-                               if (del_timer(&exp->timeout)) {
-                                       nf_ct_unlink_expect_report(exp,
-                                                       NETLINK_CB(skb).portid,
-                                                       nlmsg_report(nlh));
-                                       nf_ct_expect_put(exp);
-                               }
-                       }
-               }
-               spin_unlock_bh(&nf_conntrack_expect_lock);
+               nf_ct_expect_iterate_net(net, expect_iter_all, NULL,
+                                        NETLINK_CB(skb).portid,
+                                        nlmsg_report(nlh));
        }
 
        return 0;